¿Cómo agregar 1 milisegundos a una cadena de fecha y hora?

15

Basado en una selección, puedo devolver x filas como esta:

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

Tenemos todos los milisegundos con 0.

¿Hay alguna manera de agregar 1 por 1 milisegundos, por lo que la selección se vería así:

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

Estoy tratando de crear un cursor o incluso una actualización sin éxito.

Esta es la consulta para obtener los resultados que quiero:

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

Hay 81k valores. El campo es DATETIME.

Racer SQL
fuente
2
¿Está tratando de agregar 1 milisegundo a la fila 1, 2 milisegundos a la fila 2, 3 milisegundos a la fila 3, etc.?
John Eisbrener

Respuestas:

33

Datetimeno es preciso al nivel de 1 milisegundo. Lo que solicita no es posible a menos que cambie a un tipo de datos diferente (es decir datetime2).

Documentación

Cita importante:

Precisión redondeada a incrementos de .000, .003 o .007 segundos

Para descanso
fuente
13

La DateAddfunción es lo que estás buscando.

Úselo millisecondcomo primer parámetro de la función para indicarle que está agregando milisegundos. Luego, use 1como segundo parámetro, para la cantidad de milisegundos que se agregarán.

Aquí hay un ejemplo: tomar el tiempo actual en una variable, y luego agregarle un milisegundo y guardar el resultado como una segunda variable, y luego imprimir cada variable

Declare @RightNow as DateTime2
Declare @RightNowPlusAMillisecond as DateTime2

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

Print @RightNow
Print @RightNowPlusAMillisecond

Resultados:

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

Nota:

Como Forrest señala en otra respuesta, el datetimetipo de datos no garantiza una precisión de milisegundos. Se redondea a incrementos de .000, .003 o .007 segundos. Si desea precisión de milisegundos, use datetime2.

Doug Deden
fuente
13

@ Doug-Deden tiene el punto de partida correcto, pero solo quería intentar responder a lo que pensé que era la intención original de la pregunta: cómo aplicarlo a un conjunto de resultados con milisegundos crecientes por fila.

En ese caso, puede usar ROW_NUMBER y una expresión de tabla común (edite según sea necesario para la estructura de su tabla, incluidas las combinaciones, etc.).

Seleccione para mostrar valores:

;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

La actualización vuelve a la tabla original:

;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
fuente
Este CTE es actualizable. No es necesario volver a unirse Table1. Just doUPDATE CTE SET my_date_column =...
Steven Hibble
4

Lo he hecho usando DATETIME2(3) .

Como puede ver en la consulta a continuación, es más 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)

ingrese la descripción de la imagen aquí

Las diferencias entre datetimey datetime2están bien explicadas aquí .

Para este ejercicio, creo una tabla temporal con fines de prueba y la relleno con 999 diferentes random datesde01-jan-2019 y hoy ( 23-july-2019)

y luego en orden, configuré los milisegundos de 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

y esto es lo que obtengo: (vista parcial)

ingrese la descripción de la imagen aquí

Marcello Miorelli
fuente
2

Uno de los otros carteles es correcto; DATETIME(en T-SQL) no es exacto al milisegundo (es exacto al centisegundo).

Para ese nivel de precisión, desea utilizar DATETIME2.

Aquí hay un ejemplo de convertir una cadena datetimea datetime2, luego agregar 1 milisegundo y, por último, volver a convertir a una cadena.

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