Как добавить 1 миллисекунду к строке даты и времени?

15

Основываясь на выборе, я могу вернуть x строк следующим образом:

1   2019-07-23 10:14:04.000
1   2019-07-23 10:14:11.000
2   2019-07-23 10:45:32.000
1   2019-07-23 10:45:33.000

У нас есть все миллисекунды с 0.

Есть ли способ добавить 1 на 1 миллисекунды, так что выбор будет выглядеть так:

1   2019-07-23 10:14:04.001
1   2019-07-23 10:14:11.002
2   2019-07-23 10:45:32.003
1   2019-07-23 10:45:33.004

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

Это запрос для получения желаемых результатов:

  select top 10 ModifiedOn 
    from [SCHEMA].[dbo].[TABLE]
  where FIELD between '2019-07-23 00:00' and '2019-07-23 23:59'

Есть 81 тыс. Значений. Поле есть DATETIME.

Racer SQL
источник
2
Вы пытаетесь добавить 1 миллисекунду к строке 1, 2 миллисекунды к строке 2, 3 миллисекунды к строке 3 и т. Д.?
Джон Эйсбренер

Ответы:

33

Datetimeне является точным до уровня 1 миллисекунды. То, о чем вы просите, невозможно, если вы не переключитесь на другой тип данных (т.е. datetime2).

Документация

Важная цитата:

Точность округляется с шагом .000, .003 или .007 секунд

Форрест
источник
13

DateAddФункция то , что вы ищете.

Используйте millisecondв качестве первого параметра функции, чтобы сообщить ей, что вы добавляете миллисекунды. Затем используйте 1в качестве второго параметра количество миллисекунд для добавления.

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

Declare @RightNow as DateTime2
Declare @RightNowPlusAMillisecond as DateTime2

Select @RightNow = Getdate()
Select @RightNowPlusAMillisecond = DateAdd(millisecond,1,@RightNow)

Print @RightNow
Print @RightNowPlusAMillisecond

Результаты:

2019-07-23 08:25:38.3500000
2019-07-23 08:25:38.3510000

Замечания:

Как указывает Форрест в другом ответе, datetimeтип данных не гарантирует точность в миллисекундах. Он округляется с шагом .000, .003 или .007 секунд. Если вам нужна точность в миллисекундах, используйте datetime2.

Дуг Деден
источник
13

@ Дуг-Деден имеет правильную отправную точку, но я просто хотел попытаться ответить на то, что, как я думал, было первоначальным намерением вопроса - как применить его к результирующему набору с увеличением миллисекунд на строку.

В этом случае вы можете использовать ROW_NUMBER и Common Table Expression (отредактировать при необходимости структуру таблицы, включая объединения и т. Д.).

Выберите, чтобы показать значения:

;WITH CTE AS (
SELECT t.my_id, t.my_date_column, ROW_NUMBER() OVER (ORDER BY my_date_column, my_id DESC) AS R
FROM Table1 t
)
SELECT TOP 1000 *, DATEADD(MILLISECOND, R, CAST(my_date_column AS datetime2)) [new_date]
FROM CTE
ORDER BY my_date_column

Обновление присоединяется к исходной таблице:

;WITH CTE AS (
SELECT t.my_id, t.my_date_column, ROW_NUMBER() OVER (ORDER BY my_date_column, my_id DESC) AS R
FROM Table1 t
)
UPDATE t SET 
my_date_column = DATEADD(MILLISECOND, R, CAST(my_date_column AS datetime2))
FROM CTE c
     JOIN Table1 t ON c.my_id = t.my_id
BlueGI
источник
Этот CTE является обновляемым. Нет необходимости присоединяться к Table1. Просто сделайUPDATE CTE SET my_date_column =...
Стивен Хиббл
4

Я сделал это с помощью DATETIME2(3).

Как вы можете видеть по запросу ниже, это больше economic:

declare @dt1 datetime2(3)
declare @dt2 datetime2

SELECT @DT1 = SYSDATETIME()
SELECT @DT2=  SYSDATETIME()

SELECT [THE LENGTH OF DATETIME2]=DATALENGTH(@DT2)
      ,[THE LENGTH OF DATETIME2(3)]=DATALENGTH(@DT1)

введите описание изображения здесь

Различия между datetimeи datetime2хорошо объяснены здесь .

Для этого упражнения я создаю временную таблицу для целей тестирования и наполняю ее 999, отличным random datesот 01-jan-2019и сегодня ( 23-july-2019)

а затем по порядку я устанавливаю миллисекунды от 1 до 999

SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SET NOEXEC OFF

IF OBJECT_ID ('TEMPDB..#T1') IS NOT NULL
   DROP TABLE #T1

CREATE TABLE #t1(the_date DATETIME2(3) NOT NULL PRIMARY KEY CLUSTERED )
GO

-- run this 999 times - hopefully there will be no duplicates
-- SELECT 204*24*60*60 - today is 23-july-2019 - the 203rd day of the year
    DECLARE @DT DATETIME2(3)
    SELECT @DT = CONVERT(DATETIME2(3),
           DATEADD(SECOND, ABS(CHECKSUM(NEWID()) % 17625600), 
                   '2019-01-01'),120) 

    --SELECT @DT

    IF NOT EXISTS( SELECT 1 FROM #T1 WHERE THE_DATE = @DT) 
    INSERT INTO #T1 VALUES (@DT)
GO 999


--check it out what we have
SELECT * FROM #T1

--get the date and the new date
SELECT 
 THE_DATE
,THE_NEW_DATE= DATEADD(MILLISECOND, ROW_NUMBER() OVER (ORDER BY THE_DATE), THE_DATE ) 
 FROM #T1

и вот что я получаю: (частичный вид)

введите описание изображения здесь

Марчелло Миорелли
источник
2

Один из других постеров правильный; DATETIME(в T-SQL) не с точностью до миллисекунды (с точностью до центсекунды).

Для этого уровня точности вы хотите использовать DATETIME2.

Вот пример преобразования строки datetimeв datetime2, затем добавление 1 миллисекунды и, наконец, обратное преобразование в строку.

select convert(
            varchar(MAX), --in T-SQL, varchar length is optional
            dateadd(
                millisecond,
                1,
                convert(
                    datetime2,
                    '2019-07-23 12:01:23.11'
                )
            )
        )
McDonalds Happy Meal
источник