【问题标题】:sql store date when just the decade / century is known仅知道十年/世纪的sql存储日期
【发布时间】:2012-04-26 10:08:25
【问题描述】:

我有一个要存储在数据库中的书籍列表。其中一个属性是该书首次出版的日期。在较旧的书籍(超过 100 年)中,我通常只知道十年(例如 185X),或者如果非常古老的书籍只知道世纪(例如 15XX)。

如何将这些日期保存在 datetime2 字段中? 15XX 等于 1500?例如,我希望能够查询超过一百年的书籍。所以我想以某种方式将这些值存储为有效的 datetime2 值。有什么建议吗? 15XX 作为 '1500-01-01 00:00' 对我来说似乎是合理的。这种方法有什么缺点吗?

【问题讨论】:

  • 您可能需要考虑一个指示精度级别的标志列,或者至少将日期时间的时间部分设置为您的应用程序将解释为“日期不准确”的魔法值。以后应该有某种方法可以分辨出哪些日期是准确的,哪些是近似的(希望是多么近似!)
  • 就我个人而言,我使用了一种类似的方法,我的未知数都是 0。否则,您可以构建一个简单的类,该类包含一个日期和一个值,该值通过岁差指示已知日期的多少(即 10、100 表示最接近的十年、世纪)。
  • 另一种选择是存储 2 个代表发布日期范围的日期,当日期准确时值相同,否则它们跨越整个候选范围
  • 一如既往视情况而定。灵活性越大,开销就越多;代码/维护/性能。因此,定义您需要如何使用您的数据,然后确定最适合的数据表示。 [没有最适合所有用例的通用灵丹妙药,抱歉。]

标签: sql date


【解决方案1】:

唯一的缺点是当有人要求所有从 1550 年到 1650 年出版的书籍时。你的 15XX 变成了 1500,所以它不会包含在他的结果中。

当某本书出版时,你真正拥有的是一段不确定的时期。我会存储 2 个日期:一个是期间开始时,另一个是结束时。现代书籍会将其设置为相同的日期,但最旧的可以存储为 1500-01-01 00:00 - 1599-12-31 23:59

当然,这会使选择复杂化。你必须决定它是否值得。您可以声明要求“1550 到 1650”是愚蠢的。

【讨论】:

    【解决方案2】:

    作为@dragon112 答案的扩展,您是否有可能需要15XX 作为前两个选项的两个选项? (就像 NULL 是和不是任何值一样。)

    • 该书可能的最旧日期(对于 15xx,它将是 1500)
    • 那本书的最年轻的日期(对于 15xx 来说应该是 1599)

    如果是这样,您可以存储两个日期并确定图书出版的日期范围。

    这确实使您的查询/系统更加复杂。在编写这些 SQL 机器人时,它们在语法上是正确的,但您需要在任何给定情况下选择合适的,因为它们可能给出不同的结果...

    WHERE
      earliestPublishDate > '1550-01-01'
    
    WHERE
      latestPublishDate > '1550-01-01'
    


    因此,在确定如何存储数据时最重要的问题是:
    - 你打算怎么审问它?

    您需要了解您的用例(或可能个用例)才能确定正确的数据表示。

    【讨论】:

    • 实际上,如果有两列,查询只需要包含两个日期:'1550-01-01' BETWEEN earliestPublishDate AND latestPublishDate(针对单个日期进行测试),'1559-12-31' >= earliestPublishDate AND '1550-01-01' <= latestPublishDate(针对一个时期进行测试)。是的,比使用单列更复杂,但如果您确实需要存储不精确的日期,这似乎是一个最佳解决方案。
    • @AndriyM - 我的示例旨在强调“1550 年或之后发布”的不同解释。第一个 WHERE 子句将给出“categorically published after 1550”,而第二个子句将给出“anything that could have been published after 1550”。
    • 啊,我明白了。我认为“更复杂”是指指出系统效率可能降低,而实际上,我想,你的示例探索了复杂性增加的 积极 方面,在感觉系统将允许人们以这种额外的“精确性”来构建查询(以及它能够将这一位包含到输出中)。
    【解决方案3】:

    在我看来,有 3 种方法可以保存此类书籍的日期:

    • 该书可能的最早日期(对于 15xx,它将是 1500)
    • 该书可能的最年轻日期(对于 15xx,它将是 1599)
    • 是上述的一半(对于 15xx,它将是 1550)

    这些方法与代码本身无关,但是当您查询某个年龄时,它们会影响您的结果。所以在我看来,任何对你感觉最好的东西都应该没问题。

    换句话说,当您查询一本有 500 年历史的书时,您想得到一本 15xx 年的书吗?因为现在是 2012 年,所以数据库不会返回这本书 (2012 - 500 = 1512)。

    【讨论】:

      【解决方案4】:

      有趣的问题,我会考虑以下解决方案:

      将值保存为数据库中的两个字段。 第一个以您提到的“1500-01-01 00:00”格式存储,用于排序。第二个字段用于记录原始值15XX,其数据类型为字母数字类型。

      使用这种方法,您不会丢失数据未知的事实。但是您仍然满足搜索特定日期之前的书籍的要求。

      然后,日期时间字段严格根据字母数字字段计算得出。

      【讨论】:

      • 我非常喜欢这个建议。万一我以后想出更好的解决方案,我仍然可以访问日期字段的原始逐字值。
      • @lightxx 这根本不是“逐字记录”。您已经通过输入“15XX”强制某人丢弃一些数据。他本可以知道更具体的时期,比如 1510-1560。或者如何输入 1899-1901 年首次出版的书籍?有 3 种可能性:190X、19XX 或 1XXX,你永远不会知道这家伙的意思。
      【解决方案5】:

      如果您不需要使用日期存储时间,则使用数据类型“日期”,无需使用 datetime2 来仅允许从 01-01-0001 开始的日期。

      日期还支持从 0001-01-01 到 9999-12-31 的日期。 Datetime2 的时间精度比 datetime 高。

      【讨论】:

        【解决方案6】:
        DECLARE @var VARCHAR(100)
        SET @var = ''
        SET @var =  CASE LEN(@var) 
                        WHEN 1 THEN @var + '000' 
                        WHEN 2 THEN @var + '00' 
                        WHEN 3 THEN @var + '0' 
                        ELSE @var 
                    END
        SELECT CAST(@var AS DATE)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-11-24
          • 1970-01-01
          • 2021-08-11
          • 1970-01-01
          • 2018-03-03
          • 2017-11-14
          相关资源
          最近更新 更多