Как представить конец времени в базе данных? - PullRequest
6 голосов
/ 04 ноября 2011

Мне интересно, как представить значение конца времени (положительная бесконечность) в базе данных.

Когда мы использовали 32-битное значение времени, очевидным ответом был фактический 32-битный конец времени - что-то около года 2038 .
Теперь, когда мы используем 64-битное значение времени, мы не можем представить 64-битный конец времени в поле DATETIME, поскольку 64-битный конец времени составляет миллиарды лет с этого момента .

Поскольку SQL Server и Oracle (две наши поддерживаемые платформы) позволяют работать до 9999 лет, я подумал, что мы могли бы просто выбрать какую-нибудь "большую" будущую дату, например 1/1/3000.
Тем не менее, поскольку клиенты и наш отдел контроля качества будут следить за значениями БД, я хочу, чтобы это было очевидно и не выглядело так, как будто кто-то испортил их арифметику дат.

Мы просто выбираем дату и придерживаемся ее?

Ответы [ 5 ]

12 голосов
/ 06 ноября 2011

Используйте максимальную дату сортировки, которая, в зависимости от вашей СУБД, вероятно, будет 9999-12-31. Вы хотите сделать это, потому что запросы, основанные на диапазонах дат, быстро станут ужасно сложными, если вы попытаетесь использовать «пуристический» подход, такой как использование Null, как предлагалось некоторыми комментаторами, или использование флага навсегда, как предложено Марком Б.

Когда вы используете максимальную дату сортировки для обозначения «навсегда» или «до дальнейшего уведомления» в ваших диапазонах дат, это делает очень простые, естественные запросы. Это делает такие запросы очень понятными и простыми:

  • Найдите мне записи, которые действуют на данный момент времени.
    ... WHERE effective_date <= @PointInTime AND expiry_date >= @PointInTime
  • Найдите меня записи, которые действуют в течение следующего периода времени.
    ... WHERE effective_date <= @StartOfRange AND expiry_date >= @EndOfRange
  • Найдите мне записи с перекрывающимися диапазонами дат.
    ... WHERE A.effective_date <= B.expiry_date AND B.effective_date <= A.expiry_date
  • Найдите мне записи, у которых нет срока действия.
    ... WHERE expiry_date = @MaxCollatingDate
  • Найдите мне периоды времени, когда никакая запись не действует.
    ОК, так что это не просто, но на проще с использованием максимальных дат сопоставления для конечной точки. См: этот вопрос для хорошего подхода.

Использование этого подхода может создать небольшую проблему для некоторых пользователей, которые могут найти «9999-12-31» в отчете или на экране в замешательстве. Если это будет для вас проблемой, то предложение drdwicox об использовании перевода в удобное для пользователя значение является хорошим. Однако я хотел бы предположить, что местом для этого является уровень пользовательского интерфейса, а не средний уровень, поскольку то, что может быть наиболее разумным или приемлемым, может отличаться в зависимости от того, говорите ли вы об отчете или форме ввода данных и является ли аудитория внутренней или внешней. Например, в некоторых местах вам может понадобиться простая пробел. Другим вам может понадобиться слово «навсегда». В других случаях вам может понадобиться пустое текстовое поле с флажком «До дальнейшего уведомления».

7 голосов
/ 06 ноября 2011

В PostgreSQL конец времени равен 'бесконечности'. Он также поддерживает '-infinity'. Значение «бесконечность» гарантированно будет позже всех других временных отметок.

create table infinite_time (
  ts timestamp primary key
);

insert into infinite_time values
(current_timestamp),
('infinity');

select *
from infinite_time
order by ts;

2011-11-06 08:16:22.078
infinity

PostgreSQL поддерживает «бесконечность» и «-infinity» начиная с версии не ниже 8.0.

Вы можете имитировать это поведение, по крайней мере частично, используя максимальную дату, которую поддерживает ваша dbms. Но максимальная дата не может быть лучшим выбором. Максимальная временная метка PostgreSQL - какое-то время в году 294 276, что наверняка удивит некоторых людей. (Я не люблю удивлять пользователей.)

2011-11-06 08:16:21.734
294276-01-01 00:00:00
infinity

Подобное значение, вероятно, более полезно: '9999-12-31 11: 59: 59.999'.

2011-11-06 08:16:21.734
9999-12-31 11:59:59.999
infinity

Это не совсем максимальное значение в 9999 году, но цифры хорошо совпадают. Вы можете заключить это значение в функцию infinity () и в оператор CREATE DOMAIN. Если вы строите или поддерживаете свою структуру базы данных из исходного кода, вы можете использовать расширение макроса, чтобы расширить INFINITY до подходящего значения.

3 голосов
/ 04 ноября 2011

Иногда мы выбираем дату, а затем устанавливаем политику, согласно которой дата никогда не должна выглядеть нефильтрованной. Наиболее распространенное место для реализации этой политики находится на среднем уровне. Мы просто фильтруем результаты, чтобы изменить «волшебную» дату окончания времени на нечто более приятное.

2 голосов
/ 04 ноября 2011

Не делайте свидание особенным.Хотя маловероятно, что ваш код будет где-то в 9999 или даже в 2 ^ 63-1, посмотрите на все забавы, которые использование '12 / 31/1999 'вызвало всего несколько лет назад.

Если вам нужносигнализировать о «бесконечном» или «бесконечном» времени, затем добавить логическое / битовое поле, чтобы сигнализировать об этом состоянии.

1 голос
/ 06 ноября 2011

Представление понятия «до вечности» или «до дальнейшего уведомления» является сомнительным предложением.

Собственно реляционная теория говорит, что нет такой вещи, как нуль, поэтому вы обязаны иметь любую таблицу, в которой она разбита на две части: одна часть со строками, для которых известны дата окончания / время окончания, а другая - строки, для которых время окончания еще не известно.

Но (как и нулевое значение) разбиение таблиц на две также сделает беспорядок при написании вашего запроса. Представления могут в некоторой степени соответствовать частям, предназначенным только для чтения, но обновления (или написание INSTEAD OF на вашем представлении) будут непростыми, несмотря ни на что, и могут отрицательно повлиять на производительность, несмотря ни на что).

Наличие нулевого представления "время окончания еще не известно" сделает обновление немного "легче", но запросы чтения запутаются со всеми конструкциями CASE ... или COALESCE ..., которые вам понадобятся.

Использование теоретически правильного решения, упомянутого dportas, становится беспорядочным во всех тех случаях, когда вы хотите «извлечь» DATE из DATETIME. Если текущим значением DATETIME является «конец (представляемого) времени (как вы говорите, через миллиарды лет)», то это не просто случай вызова функции экстрактора DATE для этого значения DATETIME, поскольку также хотите, чтобы экстрактор DATE выдавал «конец представимых DATE» для вашего случая.

Плюс, вы, вероятно, не хотите показывать "отсутствующий конец времени" как значение 9999-12-31 в вашем пользовательском интерфейсе. Поэтому, если вы используете «реальное значение» конца времени в вашей базе данных, вам придется немного позаботиться о том, чтобы это значение нигде не отображалось в вашем пользовательском интерфейсе.

Извините, что не могу сказать, что есть способ остаться в стороне от всех беспорядков. Единственный выбор, который у вас есть, - какой беспорядок закончиться.

...