Добавление миллисекунд к дате и времени в tsql INSERT INTO - PullRequest
6 голосов
/ 13 апреля 2010

Я делаю запрос 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

Ответы [ 6 ]

11 голосов
/ 13 апреля 2010

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

Обновление : Если вы действительно хотите придерживаться существующего дизайна, вы можете сделать то, что просили, но используя 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
9 голосов
/ 13 апреля 2010

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

значения даты и времени округляются до с шагом .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.

2 голосов
/ 13 апреля 2010

Используйте 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
*/
1 голос
/ 13 апреля 2010

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

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

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

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

Почему?

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

1 голос
/ 13 апреля 2010

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

Но ваш оператор вставки перечисляет только три поля для вставки, но имеет четыре значения для вставки, поэтому есть еще одна проблема ...

0 голосов
/ 26 июня 2018

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

Вам нужно добавить минимум 2 миллисекунды в дату-время, чтобы новое время-дата могло быть округлено до .003, и ваши реализации будут работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...