【问题标题】:Adding milliseconds to a DateTime in TSQL INSERT INTO在 SQL INSERT INTO 中向 DateTime 添加毫秒
【发布时间】:2010-04-12 20:25:59
【问题描述】:

我正在执行 INSERT INTO 查询以初始化新表。 主键是RFQ_ID和Action_Time

如何为新记录的每个 Action_Time 添加 1 毫秒以避免“违反 PRIMARY KEY 约束”

INSERT INTO QSW_RFQ_Log
            (RFQ_ID, Action_Time, Quote_ID)
SELECT     RFQ_ID, GETDATE() AS Action_Time,  Quote_ID, 'Added to RFQ on Initialization' AS Note
FROM         QSW_Quote

【问题讨论】:

    标签: sql-server-2005 tsql


    【解决方案1】:

    仅添加 1 毫秒是行不通的,因为 SQL 中的日期时间值会四舍五入为 0.000、0.003 或 0.007 秒的增量。因此,如果您要在任何日期时间值中仅添加 1 毫秒,则不会对原始日期时间产生任何影响。

    您需要在日期时间中添加至少 2 毫秒,以便新的日期时间可以四舍五入为 .003 并且您的实现将起作用。

    【讨论】:

      【解决方案2】:

      我认为真正的问题是RFQ_ID, Action_Time 不应该是主键。创建一个surrogate 主键并在RFQ_ID, Action_Time 上放置一个非唯一索引。

      更新:如果你真的想坚持现有的设计,你可以按照你的要求做,但在每行之间使用 10 毫秒而不是 1 毫秒,以弥补日期时间的低精度。您可以使用行号来确​​定添加多少毫秒,以便为每一行获得不同的时间戳:

      INSERT INTO QSW_RFQ_Log
      (RFQ_ID, Action_Time, Quote_ID, Note)
      SELECT
        RFQ_ID,
        DATEADD(millisecond, 10 * ROW_NUMBER() OVER (ORDER BY Quote_ID), GETDATE()) AS Action_Time,
        Quote_ID,
        'Added to RFQ on Initialization' AS Note
      FROM QSW_Quote
      

      【讨论】:

      • +1 - 在其他问题上添加了一些额外的 cmets 作为答案,如果不能采用这种方法
      【解决方案3】:

      使用DATEADD,尽管重新阅读了您的问题,但我不完全确定如果您一次插入单行,为什么会遇到该问题(而且,正如其他人指出的那样,真正的问题似乎是做你的PK):

      DECLARE @datetime2 datetime2 = '2007-01-01 13:10:10.1111111'
      SELECT '1 millisecond' ,DATEADD(millisecond,1,@datetime2)
      UNION ALL
      SELECT '2 milliseconds', DATEADD(millisecond,2,@datetime2)
      UNION ALL
      SELECT '1 microsecond', DATEADD(microsecond,1,@datetime2)
      UNION ALL
      SELECT '2 microseconds', DATEADD(microsecond,2,@datetime2)
      UNION ALL
      SELECT '49 nanoseconds', DATEADD(nanosecond,49,@datetime2)
      UNION ALL
      SELECT '50 nanoseconds', DATEADD(nanosecond,50,@datetime2)
      UNION ALL
      SELECT '150 nanoseconds', DATEADD(nanosecond,150,@datetime2);
      /*
      Returns:
      1 millisecond     2007-01-01 13:10:10.1121111
      2 milliseconds    2007-01-01 13:10:10.1131111
      1 microsecond     2007-01-01 13:10:10.1111121
      2 microseconds    2007-01-01 13:10:10.1111131
      49 nanoseconds    2007-01-01 13:10:10.1111111
      50 nanoseconds    2007-01-01 13:10:10.1111112
      150 nanoseconds   2007-01-01 13:10:10.1111113
      */
      

      【讨论】:

      • 值得注意的是,这是针对 SQL Server 2008(它引入了 DATETIME2 + 纳秒参数)
      【解决方案4】:

      我同意 Mark Byers 的回答是真正的解决方案。只是想添加一个陷阱,在 SQL Server 2008 之前,日期时间精度约为 3.33 毫秒。 Quote from MSDN:

      日期时间值四舍五入为 0.000、0.003 或 0.007 的增量 第二个...

      所以在日期上加 1ms 并不能解决你的问题。

      例如

      SELECT DATEADD(ms, 1, '2010-04-12T12:00:00.000') -- outputs time still as x.000s
      SELECT DATEADD(ms, 2, '2010-04-12T12:00:00.000') -- output: .003s
      SELECT DATEADD(ms, 3, '2010-04-12T12:00:00.000') -- output: .003s
      SELECT DATEADD(ms, 4, '2010-04-12T12:00:00.000') -- output: .003s
      SELECT DATEADD(ms, 5, '2010-04-12T12:00:00.000') -- output: .007s
      SELECT DATEADD(ms, 6, '2010-04-12T12:00:00.000') -- output: .007s
      SELECT DATEADD(ms, 7, '2010-04-12T12:00:00.000') -- output: .007s
      SELECT DATEADD(ms, 8, '2010-04-12T12:00:00.000') -- output: .007s
      SELECT DATEADD(ms, 9, '2010-04-12T12:00:00.000') -- output: .010s
      

      实际上每次都需要增加 3 毫秒。充其量它适用于您的情况,但并不是真正的“干净”解决方案,有点黑客。在最坏的情况下,它只是无法工作/扩展,具体取决于数据量/数据传播的密度。但是,如果您沿着这条路线前进,您应该注意日期时间准确性问题。

      SQL Server 2008 确实引入了DATETIME2,其精度为 100ns。请参阅 DaveK 的回答。

      【讨论】:

        【解决方案5】:

        听说过“抢劫彼得付钱给保罗”吗?

        您可以操纵时间,这是一个真正的技巧,以使插入工作,但是任何并发插入呢,它们会有重叠的时间。根据您的设计,也许这永远不会发生,但多年来我学会了永远不要说永远。

        这就是我从不将日期时间作为 PK 的确切原因,它们并不总是唯一的。

        我需要行动时间作为主键, 期间。

        为什么?

        您可以将身份设置为 PK 并且仍然在 RFQ_ID+Action_Time+identity 上拥有聚集索引,这将如何真正影响您的设计或任何性能?它还可以更好地反映数据是同时添加的(每一行具有相同的日期时间)

        【讨论】:

        • 好吧,我不介意“破解”,因为它是一次性查询。我创建新表并使用另一个表中的数据对其进行初始化。然后,按天添加的记录只有 2 或 3 条。所以,我可以在主键中使用日期时间。
        【解决方案6】:

        如上所述,使用DateAdd()函数,如:

        INSERT QSW_RFQ_Log  (RFQ_ID, Action_Time, Quote_ID) 
        SELECT RFQ_ID, DateAdd(ms, 1, GETDATE()) Action_Time,  
        Quote_ID, 'Added to RFQ on Initialization' AS Note 
        FROM QSW_Quote 
        

        但是你的insert语句只列出了三个要插入的字段,却有四个要插入的值,所以还有一个问题......

        【讨论】:

        • 我修复了“要插入的三个字段”错误,实际上有十几个,但为了可见性,我把它删掉了。
        猜你喜欢
        • 2017-02-02
        • 1970-01-01
        • 1970-01-01
        • 2012-06-01
        • 2017-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-24
        相关资源
        最近更新 更多