Добавление миллисекунд в datetime в tsql INSERT в

Я делаю вставку в запрос, чтобы инициализировать новую таблицу. Первичный ключ-RFQ_ID и Action_Time

как можно добавить 1 миллисекунду к каждому Action_Time на новой записи, чтобы избежать "нарушения ограничения первичного ключа"

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 ответов


Я думаю, что реальная проблема в том, что RFQ_ID, Action_Time не должен быть первичным ключом. Создать суррогатная первичный ключ и поставить не уникальный индекс на RFQ_ID, Action_Time.

обновление: если вы действительно хотите придерживаться существующего дизайна, вы можете сделать то, что вы просили, но используя 10 миллисекунд вместо одной миллисекунды между каждой строкой, чтобы компенсировать низкую точность datetime. Вы можете использовать номер строки, чтобы определить, сколько миллисекунд добавить, чтобы получить различные метки времени для каждой строки:

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

Я бы согласился с ответом Марка Байерса как с реальным решением. Просто хотел добавить gotcha, что до SQL Server 2008 точность datetime составляет около 3,33 МС. цитата из MSDN:

значения datetime округляются до шагом .000, .003, или .Ноль ноль семь второй...

поэтому добавление 1 мс к датам не решит вашу проблему.

например

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 мс каждый раз. В лучшем случае работайте над своей ситуацией, но просто не будьте тем, что кажется "чистым" решением, немного взлома. В худшем случае он просто не будет работать/масштабироваться, в зависимости от объемов данных/плотности распространения данных. Но вы должны знать о точности datetime, если вы направляетесь по этому маршруту.

SQL Server 2008 вводит тип datetime2 который имеет точность 100ns. Увидеть DaveK ответ.


использовать функция dateadd, хотя перечитав ваш вопрос, я не совсем уверен, почему вы столкнулись с этой проблемой, если вы вставляете по одной строке за раз (и, как указывали другие, реальной проблемой, похоже, является ваш ПК):

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

как было предложено выше, используйте


вы когда-нибудь слышали о "облачении Петра, чтобы заплатить Павлу"?

вы можете манипулировать временем, которое является реальным взломом, чтобы заставить вставку работать, но как насчет любых параллельных вставок, они будут иметь перекрывающиеся времена. Возможно, это никогда не произойдет, основываясь на вашем дизайне, но я научился за эти годы никогда не говорить "никогда".

именно по этой причине я никогда не делаю datetime PK, они не всегда уникальны.

Мне нужно время действий первичный ключ, период.

почему?

вы можете сделать идентификатор PK и по-прежнему иметь кластеризованный индекс на RFQ_ID+Action_Time+identity и как это действительно повлияет на ваш дизайн или любую производительность? было бы также лучше отразить, что данные были добавлены одновременно (каждая строка с тем же datetime)


добавление только 1 миллисекунды не будет работать, поскольку значения datetime в SQL округляются до приращений .000, .003, или .007 секунду. Поэтому, если вы собираетесь добавить только 1 миллисекунду в любое значение времени даты, это не повлияет на исходное время.

вам нужно добавить минимум 2 миллисекунды в datetime, чтобы новое datetime можно было округлить .003 и ваши имплемнации сработают.