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

Я делаю запрос INSERT INTO для инициализации новой таблицы. Первичный ключ является RFQ_ID и Action_Time

Как мог добавить 1 миллисекунду к каждому Action_Time на новой записи для предотвращения "Нарушения ограничения 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
7
задан Cœur 25 March 2019 в 03:48
поделиться

5 ответов

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

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

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
12
ответ дан 6 December 2019 в 06:49
поделиться

Как было предложено выше, используйте функцию 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 

Но в инструкции yr insert перечисляются только три поля для вставки в, но имеет четыре значения, которые нужно вставить, так что есть еще одна проблема ...

1
ответ дан 6 December 2019 в 06:49
поделиться

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

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

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

SQL Server 2008 вводит DATETIME2 с точностью до 100 нс. См. Ответ DaveK.

9
ответ дан 6 December 2019 в 06:49
поделиться

Используйте 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
*/
2
ответ дан 6 December 2019 в 06:49
поделиться

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

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

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

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

ПОЧЕМУ?

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

.
2
ответ дан 6 December 2019 в 06:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: