【问题标题】:Best way to save only day and month in database在数据库中仅保存日期和月份的最佳方法
【发布时间】:2009-06-25 10:47:04
【问题描述】:

我们必须保存每年重复发生的事件的日期和月份。 (把它想象成他们一年中必须将发票发送给客户的日子。)

我们将不得不对这些信息进行一些计算。例如,如果客户每年支付两次。那么我们不仅要检查这一天是否是今天,还要检查这一天是否在 6 个月内。

我们现在有几种选择: a) 我们将信息保存在 DATE 字段中,但忽略年份。 b) 我们在数据库 date_day 和 date_month 中创建两个 int 字段。 c)我们创建一个 varchar 字段,然后执行正则表达式并拆分,例如每次我们做一些计算,31.12 起。

我们做了几次测试,发现 c) 确实太慢了。但是我们仍然可以选择 a) 和 b)。一开始我们想选择 b),但经过一些测试后,我们更倾向于 a)。

是否有充分的技术理由可以真正使一种选择比另一种更好?

(我们目前正在使用 MySQL。如果这很重要的话。)

【问题讨论】:

    标签: database database-design date


    【解决方案1】:

    我会选择 b),因为它更准确地反映了数据的含义。拥有一个应该“忽略”某些部分的数据结构是有问题的。如果人们只是进行简单的日期比较,假设年份始终相同,但有人使用不同的占位符年份,假设年份无关紧要,该怎么办?

    始终使用反映您意图的数据结构。

    我相信,c) 不好,超出了合理的讨论范围 :-)。而且我没有考虑性能原因...

    【讨论】:

    • 同意,有一个数据字段应该被忽略的部分是非常糟糕的,并且很可能会在未来咬你。我投票支持选项 b。
    • 是的,年份无关紧要。我们已经有了合同开始日期和合同结束日期。我们只需要计算是否必须发送发票。我们要做的第一个选择是检查“今天”是否在开始日期和结束日期之间。只有这样我们才能检查我们今天是否必须生成发票。
    【解决方案2】:

    我会使用日期字段,即使不需要,也会保存年份。当您必须打印/使用它时,只需将其剥离即可。有几个原因:

    1. 稍后您可能会发现 指出客户确实希望您这样做 保存日期。在这种情况下,你 不必对您的 数据库结构。
    2. 如果需要,您可以使用 SQL 日期函数来比较日期。如果您在不同的字段中有日期和月份,则需要更多代码,例如计算两个日期之间的差异(闰年等)。

    选择 b) 的原因也可以通过这些 SQL 日期函数轻松解决。您可以轻松地选择某个月份的事件,例如,在单个查询中。

    【讨论】:

    • 感谢您在闰年提醒我。这让我意识到我们忘记了以不同的方式对待二月。也许我们甚至需要像“一个月的最后一天”这样的东西作为用户的选项。这个评论对我帮助很大。即使我们决定仍然选择 b)
    【解决方案3】:

    我会选择 b),因为它会使查询更容易:您将能够以非常简单的方式恢复某个范围(12 月、特定日期、日期范围)内的所有事件。 如果您选择 a) - 出于比较和提取的原因,请不要忘记将年份设置为特定年份。

    【讨论】:

      【解决方案4】:

      我会存储第一个事件的日期,然后存储每个后续事件的时间间隔,这有点像大多数日历应用程序。在这种情况下,您可以像这样构建它:

       first_event | interval | interval_unit
      -------------+--------------------------
        2009-01-01 |        6 | 'month'
        2009-02-01 |        1 | 'year'
      

      不幸的是,MySQL 没有 INTERVAL 数据类型,因此需要两列和一些后处理,但我认为这是解决问题的最灵活的方法。

      【讨论】:

      • 我们已经有了区间和区间单位。如果年份不“重要”,问题更多是关于如何保存 first_event 。我想知道的是日期字段是否真的是后期处理的最佳选择。 (也许我对“sleske”的回答可以为您提供更多信息。)
      • 我认为如果您将第一个事件存储为 DATE,它将使计算变得更加容易。如果您总是有一年的间隔,那么只有一个 MONTH 和 DAY 列是有意义的,但是由于您的间隔可能会改变(如果您想每个月向某人收费怎么办?),我会采用日历方法.
      【解决方案5】:

      我也遇到了同样的问题,在我的情况下,我需要根据每月重复的特定日期检索数据。我使用“日期”并像这样查询

      SELECT * FROM test_table WHERE MONTH(date) = 1 AND DAY(date) = 14

      这样的结果

      优势

      1. 我可以使用 MySQL 的功能。
      2. 减少客户端计算。
      3. 可以使用 date_field 进行其他计算

      我的建议是这样使用

      这可能对某人有帮助

      【讨论】:

        【解决方案6】:

        我也支持 b),但使用 TINYINT 表示月份(0 到 255)和 SMALLINT(-32,768 到 32,767)表示年份以节省一点空间。

        【讨论】:

          【解决方案7】:

          为 1 月 1 日选择一个 int 字段,例如 1601。

          【讨论】:

          • 这个选项和“31.12”有什么显着区别?
          • 正确,但您也可以将其存储为实数。
          • @KaiHuppmann 有趣。如果你不介意你能解释一下吗?
          • @Clifford :很久以前......但我会尝试: 1. 似乎也有错字。现在是 1 月 16 日。 2. 我现在选择 116。排序等。但请注意 12 月 2 日应该是 1202,而不是 122(即 1 月 22 日) 3. 回答最初的问题:年度事件应该使用 date1 == date2 完成,每年两次 - 6-month 然后是date1 == date2 OR date1+600 == date2(先排序日期)
          【解决方案8】:

          我会选择年份数字(例如,从 0 到 365 的单个数字,然后将其添加到您感兴趣的特定年份的 1 月 1 日。

          如果您不想对上述解决方案进行额外的数学运算,请使用两个字段,一个用于月,一个用于天(但请确保在需要时更新这两个字段!)。

          请记住,您必须处理闰年,因此使用日期字段不是一个好主意,因为您必须存储两年的日期 - 一个是闰年,另一个不是 - 非常复杂!

          【讨论】:

          • 闰年正是“一年中的某一天”不适用于此的原因 - 如果您存储“60”,那么在闰年您将在 2 月 29 日付款,在匹配 1 的非闰年- 现实世界的付款时间表不会这样做。
          • 是的,虽然它不依赖于业务规则。我想我会在 28 日之后的几天内将一年中的日期数字向后移动几天以纠正这一点 - e
          猜你喜欢
          • 2018-05-25
          • 2021-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-01
          • 2012-02-02
          相关资源
          最近更新 更多