Come aggiungere 1 millisecondi a una stringa datetime?


15

Sulla base di una selezione, posso restituire x righe in questo modo:

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

Abbiamo tutti i millisecondi con 0.

C'è un modo per aggiungere 1 per 1 millisecondi, quindi la selezione dovrebbe apparire così:

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

Sto cercando di creare un cursore o anche un aggiornamento senza successo.

Questa è la query per ottenere i risultati desiderati:

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

Ci sono 81k valori. Il campo è DATETIME.


2
Stai cercando di aggiungere 1 millisecondo alla riga 1, 2 millisecondi alla riga 2, 3 millisecondi alla riga 3, ecc.?
John Eisbrener,

Risposte:


33

Datetimenon è preciso al livello di 1 millisecondo. Quello che stai chiedendo non è possibile a meno che non passi a un tipo di dati diverso (es datetime2.).

Documentazione

Citazione importante:

Precisione arrotondata a incrementi di 0,00000, 0,003 o 0,007 secondi


13

Il DateAdd funzione è ciò che stai cercando.

Utilizzare millisecondcome primo parametro per la funzione, per dire che si stanno aggiungendo millisecondi. Quindi utilizzare 1come secondo parametro, per il numero di millisecondi da aggiungere.

Ecco un esempio, afferrando l'ora corrente in una variabile, quindi aggiungendo un millisecondo ad essa e salvando il risultato come seconda variabile, quindi stampando ogni variabile

Declare @RightNow as DateTime2
Declare @RightNowPlusAMillisecond as DateTime2

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

Print @RightNow
Print @RightNowPlusAMillisecond

risultati:

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

Nota:

Come sottolinea Forrest in un'altra risposta, il datetimetipo di dati non garantisce una precisione di millisecondi. Arrotonda per eccesso a .000, .003 o .007 secondi. Se si desidera la precisione in millisecondi, utilizzare datetime2.


13

@ Doug-Deden ha il punto di partenza giusto, ma volevo solo provare a rispondere a ciò che pensavo fosse l'intenzione originale della domanda: come applicarla a un set di risultati con millisecondi in aumento per riga.

In tal caso, puoi utilizzare ROW_NUMBER e un'espressione di tabella comune (modifica in base alle esigenze per la struttura della tabella, inclusi i join, ecc.).

Selezionare per mostrare i valori:

;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

L'aggiornamento si ricollega alla tabella originale:

;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

Questo CTE è aggiornabile. Non è necessario iscriversi di nuovo a Table1. Basta fareUPDATE CTE SET my_date_column =...
Steven Hibble il

4

L'ho fatto usando DATETIME2(3).

Come puoi vedere nella query qui sotto, è di più 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)

inserisci qui la descrizione dell'immagine

Le differenze tra datetimee datetime2sono ben spiegate qui .

Per questo esercizio creo una tabella temporanea a scopo di test e la popolo con 999 diversi random datesda 01-jan-2019e oggi ( 23-july-2019)

e poi in ordine, ho impostato i millisecondi da 1 a 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

e questo è quello che ottengo: (vista parziale)

inserisci qui la descrizione dell'immagine


2

Uno degli altri poster è corretto;DATETIME(in T-SQL) non è preciso al millisecondo (è preciso al centisecondo).

Per quel livello di precisione, vuoi usare DATETIME2.

Ecco un esempio di conversione di una stringa datetimein datetime2, quindi aggiunta di 1 millisecondo e, infine, conversione in stringa.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.