Wie füge ich einer datetime-Zeichenfolge 1 Millisekunde hinzu?


15

Basierend auf einer Auswahl kann ich x Zeilen wie folgt zurückgeben:

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

Wir haben alle Millisekunden mit 0.

Gibt es eine Möglichkeit, 1 mal 1 Millisekunden hinzuzufügen, so dass die Auswahl folgendermaßen aussehen würde:

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

Ich versuche, einen Cursor oder sogar ein Update ohne Erfolg zu erstellen.

Dies ist die Abfrage, um die gewünschten Ergebnisse zu erhalten:

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

Es gibt 81k-Werte. Das Feld ist DATETIME.


2
Versuchen Sie, 1 Millisekunde zu Zeile 1, 2 Millisekunden zu Zeile 2, 3 Millisekunden zu Zeile 3 usw. hinzuzufügen?
John Eisbrener

Antworten:


33

Datetimeist nicht genau auf 1 Millisekunde genau. Was Sie verlangen, ist nur möglich, wenn Sie zu einem anderen Datentyp (dh datetime2) wechseln .

Dokumentation

Wichtiges Zitat:

Genauigkeit Auf Schritte von .000, .003 oder .007 Sekunden gerundet


13

Die DateAddFunktion ist was Sie suchen.

Verwenden Sie millisecondals ersten Parameter der Funktion, um anzugeben, dass Sie Millisekunden hinzufügen. Verwenden Sie dann 1als zweiten Parameter die Anzahl der hinzuzufügenden Millisekunden.

In diesem Beispiel wird die aktuelle Zeit in eine Variable übernommen, eine Millisekunde hinzugefügt, das Ergebnis als zweite Variable gespeichert und anschließend jede Variable gedruckt

Declare @RightNow as DateTime2
Declare @RightNowPlusAMillisecond as DateTime2

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

Print @RightNow
Print @RightNowPlusAMillisecond

Ergebnisse:

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

Hinweis:

Wie Forrest in einer anderen Antwort ausführt, datetimegarantiert der Datentyp keine Millisekundengenauigkeit. Es wird in Schritten von .000, .003 oder .007 Sekunden gerundet. Wenn Sie Millisekundengenauigkeit wünschen, verwenden Sie datetime2.


13

@ Doug-Deden hat den richtigen Ausgangspunkt, aber ich wollte nur versuchen, die ursprüngliche Absicht der Frage zu beantworten - wie man sie auf eine Ergebnismenge mit zunehmenden Millisekunden pro Zeile anwendet.

In diesem Fall können Sie ROW_NUMBER und einen allgemeinen Tabellenausdruck verwenden (wie für Ihre Tabellenstruktur erforderlich bearbeiten, einschließlich Verknüpfungen usw.).

Auswählen, um Werte anzuzeigen:

;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

Update kehrt zur ursprünglichen Tabelle zurück:

;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

Dieser CTE ist aktualisierbar. Keine Notwendigkeit, sich wieder anzumelden Table1. Tun Sie einfachUPDATE CTE SET my_date_column =...
Steven Hibble

4

Ich habe es mit gemacht DATETIME2(3).

Wie Sie in der folgenden Abfrage sehen können, handelt es sich um mehr 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)

Bildbeschreibung hier eingeben

Die Unterschiede zwischen datetimeund datetime2sind gut erklärt hier .

Für diese Übung erstelle ich zu Testzwecken eine temporäre Tabelle und fülle sie mit 999 anderen random datesals 01-jan-2019und heute ( 23-july-2019)

und dann in der richtigen Reihenfolge stelle ich die Millisekunden von 1 bis 999 ein

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

und das bekomme ich: (Teilansicht)

Bildbeschreibung hier eingeben


2

Eines der anderen Plakate ist richtig; DATETIME(in T-SQL) ist nicht millisekundengenau (es ist zentisekundengenau).

Für diese Genauigkeit möchten Sie verwenden DATETIME2.

Hier ist ein Beispiel für das Konvertieren einer Zeichenfolge datetimein datetime2, das Hinzufügen von 1 Millisekunde und das Zurückkonvertieren in eine Zeichenfolge.

select convert(
            varchar(MAX), --in T-SQL, varchar length is optional
            dateadd(
                millisecond,
                1,
                convert(
                    datetime2,
                    '2019-07-23 12:01:23.11'
                )
            )
        )

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.