在sql INSERT INTO中向datetime添加毫秒

时间:2010-04-12 20:25:59

标签: sql-server-2005 tsql

我正在进行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

6 个答案:

答案 0 :(得分:11)

我认为真正的问题是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 :(得分:9)

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

  

日期时间值四舍五入为   .000,.003或.007的增量   第二...

因此,向日期添加1毫秒将无法解决您的问题。

e.g。

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

实际上你需要每次增加3ms。充其量它可以适用于你的情况,但只是不是真正的感觉像一个“干净”的解决方案,一点点黑客。在最坏的情况下,它根本不会工作/扩展,具体取决于数据量/数据传播的密度。但是,如果你沿着这条路走下去,你应该知道日期时间的准确性。

SQL Server 2008确实引入了DATETIME2,其准确度为100ns。见DaveK的回答。

答案 2 :(得分:2)

使用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
*/

答案 3 :(得分:1)

如上所述,使用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 

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

答案 4 :(得分:1)

曾经听说过“抢劫彼得要付保罗”吗?

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

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

  

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

为什么?

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

答案 5 :(得分:0)

仅添加1毫秒是无效的,因为SQL中的日期时间值被四舍五入为.000,.003或.007秒。因此,如果您要在任何日期时间值中仅添加1毫秒,则对原始日期时间不会有任何影响。

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