【问题标题】:What can bite me if I store a datetime as a float in the database?如果我将日期时间作为浮点数存储在数据库中,会受到什么影响?
【发布时间】:2023-03-29 15:17:01
【问题描述】:

如果我将日期时间作为浮点数存储在数据库中,会有什么问题?我有一个很好的理由这样做,所以不要抱怨:)

编辑:我正在考虑将 convert(float, @thedate) 存储在浮点列中。

【问题讨论】:

  • 你的理由是什么?对于初学者,我想你会遇到精度问题。
  • 你是如何存储它的?作为某个时代以来经过的时间的计数?还是某种文字表示?
  • 您将日期时间存储为浮点数的原因是什么?
  • 不知道,这是 10 年前的事了

标签: sql-server datetime


【解决方案1】:

什么能咬你?那么第一个浮点数不是一个精确的数据类型,因此可能永远不应该用于任何需要精度的东西。接下来,float 不会自动拒绝错误的日期。接下来,如果您想执行任何日期功能,您首先必须将数据转换回日期时间数据类型,这会浪费服务器资源。

您说您有充分的理由想要这样做,但在知道这可能是什么的情况下,我认为日期应该存储在用于处理它们的数据类型中。

【讨论】:

  • +1 表示“浮动不会自动拒绝错误的日期。”
  • 如果浮点数是儒略日期,例如,没有“不正确的日期”,只是更精细的分辨率或更大的时间范围。
  • 示例:select cast(cast(2958464 as float) as datetime)
  • (对于 SQL Server,这会给出“将表达式转换为数据类型日期时间的算术溢出错误。”)
  • 嗯,这是 SQLServer 实现的限制,而不是格式本身。
【解决方案2】:

这是一篇关于“揭秘 SQL Server DATETIME 数据类型”的好文章

http://www.sql-server-performance.com/articles/dev/datetime_datatype_p1.aspx

从阅读中可以看出,日期时间似乎存储为 2 个 4 字节整数,或者您可以使用 binary(8)

正如其他人所说,存储为浮点数会导致您失去一些精度。

【讨论】:

    【解决方案3】:

    Alan 说的,加上……维护的根本问题;当其他人进入项目,并在数据库中看到日期时间的浮点数,并尝试对其做错事,或尝试将其重构为正确的类型,或者只是花费数小时仔细研究代码以找出什么是哎呀正在发生。通过大量记录正在发生的事情以及为什么要这样做,可以在一定程度上缓解整个维护问题,我强烈建议这样做。

    【讨论】:

    • 我愿意承担维修问题。正如我所说,我这样做是有充分理由的。
    • 我并不是说你不应该这样做(尽管我可能应该这样做);这是你的选择;我只是在回答什么会咬你的问题。至少,我建议您记录下您为什么要这样做,以缓解维护问题。
    【解决方案4】:

    SQLite 使用带有(64 位)双浮点的时间格式(其中一种可用),整数部分表示自纪元以来的天数,小数部分表示一天的小数部分。它似乎运作良好。

    请参阅SQLite Date and Time Functions“格式 12 是用浮点值表示的儒略日数。”

    使用Julian Dates 15 位十进制数字可以获得几千年的毫秒精度。

    根据this Julian Date Converter,JD 9999999.99999 是 CE 22666 December 20 11:59:59.1 UT Thursday

    【讨论】:

      【解决方案5】:

      一个的精度损失。缺乏分辨率是另一个原因。

      这是一个小问题,但浮点版本 IEEE 754 与 VAX 浮点。

      【讨论】:

      • 但请注意,您可以计算:例如,一个 8 字节的 int(或 float)足以以微秒精度存储 584000 年(256**8 / 1.000.000 / 60 / 60 / 24 / 365)。
      【解决方案6】:

      你失去了一些精度。我在 SQL Server 中进行了测试:

      select getdate(), cast(getdate() as float), cast(cast(getdate() as float) as datetime)
      

      您可以看到如果您重复运行此程序,您可能会在转换中损失多达 4 毫秒。如果您的数据库支持 smalldatetime 之类的数据类型,并且您只需要精确到秒,那么您可以消除这种差异。

      【讨论】:

      • 你应该用静态日期来做。
      • --这是一个很好的例子...声明@d datetime; set @d = '2009-05-27 16:33:54.260' select @d, cast(cast(@d as float) as datetime), cast(cast(cast(cast(@d as float) as datetime) as浮动)作为日期时间)
      • 这实际上是一个静态日期,你永远不会在一个语句中使用 getdate() 返回不同的日期。
      【解决方案7】:

      实际上,据我所知,MSSQL 和 Oracle 实际上确实在内部将日期时间存储为浮点数(如天数和小数天数)

      select cast(0 as datetime), cast(0.5 as datetime)
      1900-01-01 00:00:00.000 1900-01-01 12:00:00.000
      

      【讨论】:

      • 这并不能证明日期被存储为浮点数,它只证明它们有一个浮点数->转换日期
      【解决方案8】:

      无论精度如何 - 根据您选择的数字作为起点,您可能无法进行比较。

      如果您无法为每个日期时间创建精确的浮点数,则您可能还有两个日期时间,如果它们解析为不同的浮点数,则可以同时比较一种方式和另一种方式。

      【讨论】:

        【解决方案9】:

        使用浮点数的一个潜在缺点是您无法使用系统的内置日期操作函数。如果您只进行间隔计算,浮点数可能没问题,但与日历相关的任何事情都可能需要重新发明。

        顺便说一句,Oracle 似乎至少使用固定字段来表示其内部日期:

        选择 to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') 作为 Date_Value, 转储(sysdate)作为内部 从双; DATE_VALUE 内部 ------- -------------------------------------------- ----------------------------------------- 2009-05-28 09:51:12 Typ=13 Len=8: 217,7,5,28,9,51,12,0 已选择 1 行

        【讨论】:

          【解决方案10】:

          如果您要将这些数据存储为浮点数,我认为您最好将自纪元以来的秒数存储为浮点数,而不是将日期时间存储为浮点数

          【讨论】:

            猜你喜欢
            • 2010-10-07
            • 2011-02-04
            • 2019-04-01
            • 1970-01-01
            • 2011-04-17
            • 1970-01-01
            • 2021-05-29
            • 1970-01-01
            • 2011-09-26
            相关资源
            最近更新 更多