【问题标题】:How to store absolute and relative date ranges in SQL database?如何在 SQL 数据库中存储绝对和相对日期范围?
【发布时间】:2011-09-30 12:54:22
【问题描述】:

我正在尝试为报告应用程序建模 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
)

或

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

感谢您的建议!

【问题讨论】:

    标签: sql schema date-range


    【解决方案1】:

    我不明白为什么你的第二个设计不能满足你的需求,除非你在“no NULLs never”阵营中。只需将 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
    

    【讨论】:

    • 我对 NULL 不感兴趣,但我讨厌 RDBS 中的上下文列,即“仅当 B 列为空且 C 列代表不同的事物时,才填充 A 列,具体取决于填充的 A 或 B。 "
    • 好吧,这里向您展示了两个既不同又相同的实体。不同之处在于两者中的一个具有与之关联的额外数据。您要么需要一个具有细微变化的表,要么需要两个不同的表。
    • 我喜欢将存储表与表示当前日期的 NULL 组合,然后使用“已解决”视图来适当地呈现这些日期的想法。谢谢!
    【解决方案2】:

    其他是相对于当前日期、过去 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
    

    【讨论】:

      【解决方案3】:

      将它们放在不同的表格中。绝对没有理由将它们放在一个表中。

      对于相对日期,我什至只是简单地将表格设置为日期函数所需的参数,即

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

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

      如果您需要同时查看它们,您可以将它们逻辑地组合到一个查询或视图中,而无需通过将不同的数据元素塞入同一个表中来弄乱您的数据结构。

      【讨论】:

      • 好吧,我想把它用作一个包含布局和定义的报表表的 FK。在这种情况下,使用两个表会变得更加复杂,不是吗?
      • @ant - 不是真的,只是在你的另一张桌子上把它变成一个 2 部分的 FK。 Range 或 Relative,以及 ID。然后您仍然可以强制执行关系,但您不必将所有内容都放在一个表中。
      【解决方案4】:

      创建一个包含开始日期和偏移量的表。偏移的精度由您决定。

      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之类的东西。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-19
        • 2015-03-15
        • 2019-12-03
        • 1970-01-01
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多