如何在SQL数据库中存储绝对和相对日期范围?

时间:2011-09-30 12:54:23

标签: sql schema date-range

我正在尝试为报告应用程序建模DateRange概念。某些日期范围必须是绝对的,2011年3月1日 - 2011年3月31日。其他日期范围相对于当前日期,过去30天,下周等。在SQL表中存储该数据的最佳方法是什么?

显然对于绝对范围,我可以有一个BeginDate和EndDate。对于相对范围,具有InceptionDate和整数RelativeDays列是有意义的。如何将这两个想法合并到单个表中而不在其中实现上下文,即提及所有四列并使用XOR逻辑来填充4中的2个。

由于具有上下文驱动的列,我拒绝了两种可能的模式:

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 个答案:

答案 0 :(得分:2)

我不明白为什么你的第二个设计不能满足你的需求,除非你处于“从不虚无”的阵营。只需将InceptionDate留给“相对于当前日期”选项,以便您的应用程序可以将它们与固定日期范围分开。

(注意:不知道你的数据库引擎,我在伪代码中留下了日期数学和当前日期问题。另外,在你的问题中,我遗漏了任何文字描述和主键列。)

然后,创建一个这样的视图:

 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 :(得分:1)

  

其他与当前日期,过去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

答案 2 :(得分:0)

将它们放在单独的表格中。绝对没有理由将它们放在一张表中。

对于相对日期,我甚至可以简单地使表格成为日期函数所需的参数,即

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

然后,您可以知道它是-2 WEEK30 DAY方差并在您的逻辑中使用它。

如果你需要同时看到它们,你可以在查询或视图中将它们组合成LOGICALLY,而不需要通过将不同的数据元素塞进同一个表来搞乱你的数据结构。

答案 3 :(得分:0)

创建一个包含begindate和偏移量的表。偏移的精度由您决定。

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

如果您希望能够解析“原始”模糊描述,则必须寻找“模糊日期”或“近似”功能。 (在git源代码中存在类似this的东西。)