it-swarm.it

Come aggiungere 1 millisecondi a una stringa datetime?

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.

15
Racer SQL

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

Documentazione

Citazione importante:

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

33
Forrest

La funzione DateAdd è ciò che stai cercando.

Usa millisecond come primo parametro per la funzione, per dire che stai aggiungendo millisecondi. Quindi usa 1 come 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 tipo di dati datetime non garantisce una precisione di millisecondi. Arrotonda a incrementi di 0,00000, 0,003 o 0,007 secondi. Se vuoi la precisione in millisecondi, usa datetime2.

13
Doug Deden

@ 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 applicarlo a un set di risultati con millisecondi in aumento per riga.

In tal caso, puoi utilizzare ROW_NUMBER e un Common Table Expression (modifica secondo necessità 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
13
BlueGI

L'ho fatto usando DATETIME2(3).

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

enter image description here

Le differenze tra datetime e datetime2 sono ben spiegate qui .

Per questo esercizio creo una tabella temporanea a scopo di test e la popolo con 999 diversi random dates a partire dal 01-jan-2019 e 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)

enter image description here

4

no 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 datetime in datetime2, quindi aggiungendo 1 millisecondo e infine convertendo nuovamente in una stringa.

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