Jak dodać 1 milisekundę do ciągu datetime?

15

Na podstawie zaznaczenia mogę zwrócić x wierszy w następujący sposób:

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

Wszystkie milisekundy mają 0.

Czy istnieje sposób na dodanie 1 na 1 milisekundę, więc zaznaczenie wyglądałoby tak:

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

Próbuję utworzyć kursor, a nawet aktualizację bez powodzenia.

To jest zapytanie, aby uzyskać pożądane wyniki:

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

Jest 81k wartości. To pole jest DATETIME.

Racer SQL
źródło
2
Czy próbujesz dodać 1 milisekundę do wiersza 1, 2 milisekundy do wiersza 2, 3 milisekundy do wiersza 3 itd.?
John Eisbrener,

Odpowiedzi:

33

Datetimenie jest dokładny do poziomu 1 milisekundy. To, o co prosisz, nie jest możliwe, chyba że zmienisz inny typ danych (tj datetime2.).

Dokumentacja

Ważny cytat:

Dokładność Zaokrąglona do przyrostów 0,000, 0,003 lub 0,007 sekundy

Forrest
źródło
13

The DateAddFunkcją jest to, czego szukasz.

Użyj millisecondjako pierwszego parametru do funkcji, aby powiedzieć jej, że dodajesz milisekundy. Następnie użyj1 jako drugiego parametru liczby milisekund do dodania.

Oto przykład, pobieranie bieżącego czasu do zmiennej, a następnie dodawanie do niego jednej milisekundy i zapisywanie wyniku jako drugiej zmiennej, a następnie drukowanie każdej zmiennej

Declare @RightNow as DateTime2
Declare @RightNowPlusAMillisecond as DateTime2

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

Print @RightNow
Print @RightNowPlusAMillisecond

Wyniki:

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

Uwaga:

Jak Forrest wskazuje w innej odpowiedzi, datetimetyp danych nie gwarantuje precyzji w milisekundach. Zaokrągla to z dokładnością do 0,000, 0,003 lub 0,007 sekundy. Jeśli chcesz mieć milisekundową precyzję, użyj datetime2.

Doug Deden
źródło
13

@ Doug-Deden ma właściwy punkt wyjścia, ale chciałem tylko spróbować odpowiedzieć na to, co według mnie było pierwotnym zamiarem pytania - jak zastosować je do zestawu wyników ze wzrostem milisekund na wiersz.

W takim przypadku możesz użyć ROW_NUMBER i wspólnego wyrażenia tabelowego (edytuj w razie potrzeby strukturę tabeli, w tym sprzężenia itp.).

Wybierz, aby wyświetlić wartości:

;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

Aktualizacja łączy ponownie do oryginalnej tabeli:

;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
źródło
Ten CTE można aktualizować. Nie musisz dołączać ponownie Table1. Po prostu zróbUPDATE CTE SET my_date_column =...
Steven Hibble
4

Zrobiłem to za pomocą DATETIME2(3).

Jak widać na poniższym zapytaniu, jest więcej 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)

wprowadź opis zdjęcia tutaj

Różnice między datetimei datetime2tutaj dobrze wyjaśnione .

W tym ćwiczeniu tworzę tabelę tymczasową do celów testowych i wypełniam ją wartością 999 inną random datesniż 01-jan-2019obecnie ( 23-july-2019)

a następnie w kolejności ustawiam milisekundy od 1 do 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

i oto co otrzymuję: (częściowy widok)

wprowadź opis zdjęcia tutaj

Marcello Miorelli
źródło
2

Jeden z pozostałych plakatów jest poprawny; DATETIME(w T-SQL) nie jest dokładny do milisekundy (jest dokładny do centisekundy).

Dla tego poziomu dokładności chcesz użyć DATETIME2 .

Oto przykład konwersji łańcucha datetimena datetime2, następnie dodania 1 milisekundy, a na koniec konwersji z powrotem na łańcuch.

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
źródło