Як додати 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'

Є значення 81k. Поле є DATETIME.


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 та загальний вираз таблиці (відредагуйте, як потрібно для вашої структури таблиці, включаючи приєднання тощо).

Виберіть для відображення значень:

;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

Цей 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'
                )
            )
        )

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.