Как хранить абсолютные и относительные диапазоны дат в базе данных SQL? - PullRequest
2 голосов
/ 30 сентября 2011

Я пытаюсь смоделировать концепцию DateRange для приложения отчетности. Некоторые диапазоны дат должны быть абсолютными, 1 марта 2011 г. - 31 марта 2011 г. Другие относятся к текущей дате, последним 30 дням, следующей неделе и т. Д. Каков наилучший способ хранения этих данных в таблице SQL?

Очевидно, что для абсолютных диапазонов у меня могут быть BeginDate и EndDate. Для относительных диапазонов целесообразно иметь столбец InceptionDate и целочисленный столбец RelativeDays. Как мне объединить обе эти идеи в одну таблицу без внедрения в нее контекста, то есть упомянуть все четыре столбца и использовать логику XOR для заполнения 2 из 4.

Две возможные схемы, которые я отклонил из-за наличия столбцов, управляемых контекстом:

CREATE TABLE DateRange
(
    BeginDate DATETIME NULL,
    EndDate DATETIME NULL,
    InceptionDate DATETIME NULL,
    RelativeDays INT NULL
)

OR

CREATE TABLE DateRange
(
    InceptionDate DATETIME NULL,
    BeginDaysRelative INT NULL,
    EndDaysRelative INT NULL
)

Спасибо за любой совет!

Ответы [ 4 ]

2 голосов
/ 30 сентября 2011

Я не понимаю, почему ваш второй дизайн не соответствует вашим потребностям, если вы не находитесь в лагере «никогда не пустые».Просто оставьте InceptionDate NULL для выбора «относительно текущей даты», чтобы ваше приложение могло отличить их от фиксированных диапазонов дат.

(Примечание: не зная ваш механизм БД, я оставил данные по математике и текущей датев псевдокоде. Также, как и в вашем вопросе, я пропустил любое текстовое описание и столбцы первичного ключа).

Затем либо создайте вид, подобный этому:

 CREATE VIEW DateRangesSolved (Inception, BeginDays, EndDays) AS
    SELECT CASE WHEN Inception IS NULL THEN Date() ELSE Inception END,
           BeginDays,
           EndDays,
    FROM DateRanges

используйте эту логику, когда вы выбираете из таблицы напрямую.

Вы можете сделать еще один шаг вперед:

 CREATE VIEW DateRangesSolved (BeginDate, EndDate) AS
    SELECT (CASE WHEN Inception IS NULL THEN Date() ELSE Inception END + BeginDays),
           (CASE WHEN Inception IS NULL THEN Date() ELSE Inception END + EndDays)
    FROM DateRanges
1 голос
/ 30 сентября 2011

Другие значения относятся к текущей дате, последним 30 дням, следующей неделе и т. Д. Каков наилучший способ хранить эти данные в таблице SQL?

Если вы храните эти диапазоны в таблице, вы должны обновлять их каждый день. В этом случае вы должны обновлять каждую строку по-разному каждый день. Это может быть большой проблемой; это не может быть.

Обычно в такой таблице не так много строк, часто меньше 50. Структура таблицы очевидна. Обновление должно выполняться заданием cron (или его эквивалентом), и вы должны запускать очень требовательные отчеты об исключениях каждый день, чтобы убедиться, что все обновлено правильно.

Как правило, отчеты такого типа не должны давать результатов, если все в порядке. У вас есть дополнительное усложнение, что вывод такого отчета из cron не будет производить вывод, если cron не запущен. И это не хорошо.

Вы также можете создать представление, которое не требует обслуживания. С несколькими десятками строк он может быть медленнее, чем физическая таблица, но все равно может быть достаточно быстрым. И это исключает все обслуживание и административную работу для этих диапазонов. (Проверьте наличие ошибок, потому что я этого не сделал.)

create view relative_date_ranges as 
select 'Last 30 days' as range_name, 
        (current_date - interval '30' day)::date as range_start, 
        current_date as range_end
union all
select 'Last week' as range_name, 
       (current_date - interval '7' day)::date as range_start, 
       current_date as range_end
union all 
select 'Next week' as range_name, 
       (current_date + interval '7' day)::date as range_start, 
       current_date as range_end

В зависимости от приложения вы можете обрабатывать «абсолютные» диапазоны одинаково.

...
union all
select 'March this year' as range_name, 
       (extract(year from current_date) || '-03-01')::date as range_start, 
       (extract(year from current_date) || '-03-31')::date as range_end
0 голосов
/ 30 сентября 2011

Создайте таблицу, содержащую начало и смещение. Точность смещения зависит от вас.

CREATE TABLE DateRange(
    BeginDate DATETIME NOT NULL,
    Offset int NOT NULL,
    OffsetLabel varchar(100)
)

вставить в него:

INSERT INTO DateRange (BeginDate, Offset, OffsetLabel)
 select '20110301', DATEDIFF(sec, '20110301', '20110331'), 'March 1, 2011 - March 31, 2011'

Последние 30 дней

 INSERT INTO DateRange (BeginDate, Duration, OffsetLabel)
 select '20110301', DATEDIFF(sec, current_timestamp, DATEADD(day, -30, current_timestamp)), 'Last 30 Days'

Чтобы отобразить значения позже:

select BeginDate, EndDate = DATEADD(sec, Offset, BeginDate), OffsetLabel
from DateRange

Если вы хотите иметь возможность анализировать «оригинальные» расплывчатые описания, вам придется искать функцию «Нечеткая дата» или «Приближенное». (Существует нечто вроде this в исходном коде git.)

0 голосов
/ 30 сентября 2011

Поместите их в отдельные таблицы. Нет абсолютно никаких причин, чтобы иметь их в одной таблице.

Для относительных дат я бы зашел настолько далеко, что просто сделал в таблице параметры, необходимые для функций даты, т.е.

CREATE TABLE RelativeDate
(
    Id INT Identity,
    Date_Part varchar(25),
    DatePart_Count int
)

Тогда вы можете знать, что это -2 WEEK или 30 DAY дисперсия, и использовать это в своей логике.

Если вам нужно увидеть их обоих одновременно, вы можете ЛОГИЧЕСКИ объединить их в запросе или представлении, не прибегая к путанице в вашей структуре данных, помещая различные элементы данных в одну таблицу.

...