Comment ajouter 1 millisecondes à une chaîne datetime?

15

Sur la base d'une sélection, je peux retourner x lignes comme ceci:

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

Nous avons toutes les millisecondes avec 0.

Existe-t-il un moyen d'ajouter 1 par 1 millisecondes, de sorte que la sélection ressemble à ceci:

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

J'essaie de créer un curseur ou même une mise à jour sans succès.

Voici la requête pour obtenir les résultats que je souhaite:

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

Il y a 81k valeurs. Le champ est DATETIME.

Racer SQL
la source
2
Essayez-vous d'ajouter 1 milliseconde à la ligne 1, 2 millisecondes à la ligne 2, 3 millisecondes à la ligne 3, etc.?
John Eisbrener

Réponses:

33

Datetimen'est pas précis au niveau de 1 milliseconde. Ce que vous demandez n'est possible que si vous changez de type de données (c. datetime2-à-d.).

Documentation

Citation importante:

Précision Arrondie à des incréments de .000, .003 ou .007 secondes

Forrest
la source
13

La DateAddfonction est ce que vous recherchez.

Utilisez millisecondcomme premier paramètre de la fonction pour lui indiquer que vous ajoutez des millisecondes. Utilisez ensuite 1comme deuxième paramètre, le nombre de millisecondes à ajouter.

Voici un exemple, en saisissant l'heure actuelle dans une variable, puis en y ajoutant une milliseconde et en enregistrant le résultat en tant que deuxième variable, puis en imprimant chaque variable

Declare @RightNow as DateTime2
Declare @RightNowPlusAMillisecond as DateTime2

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

Print @RightNow
Print @RightNowPlusAMillisecond

Résultats:

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

Remarque:

Comme Forrest le fait remarquer dans une autre réponse, le datetimetype de données ne garantit pas la précision en millisecondes. Il arrondit à des incréments de .000, .003 ou .007 secondes. Si vous voulez une précision en millisecondes, utilisez datetime2.

Doug Deden
la source
13

@ Doug-Deden a le bon point de départ, mais je voulais juste essayer de répondre à ce que je pensais être l'intention initiale de la question - comment l'appliquer à un jeu de résultats avec des millisecondes croissantes par ligne.

Dans ce cas, vous pouvez utiliser ROW_NUMBER et une expression de table commune (modifiez selon les besoins pour la structure de votre table, y compris les jointures, etc.).

Sélectionnez pour afficher les valeurs:

;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

Mettre à jour les jointures à la table d'origine:

;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
la source
Ce CTE est modifiable. Pas besoin de revenir à Table1. UPDATE CTE SET my_date_column =...
Faites
4

Je l'ai fait en utilisant DATETIME2(3).

Comme vous pouvez le voir sur la requête ci-dessous, c'est plus 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)

entrez la description de l'image ici

Les différences entre datetimeet datetime2sont bien expliquées ici .

Pour cet exercice, je crée une table temporaire à des fins de test et je la remplis avec 999 différentes random datesde celles d' 01-jan-2019aujourd'hui ( 23-july-2019)

puis dans l'ordre, j'ai mis les millisecondes de 1 à 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

et voici ce que j'obtiens: (vue partielle)

entrez la description de l'image ici

Marcello Miorelli
la source
2

L'une des autres affiches est correcte; DATETIME(en T-SQL) n'est pas précis à la milliseconde (il est précis à la centiseconde).

Pour ce niveau de précision, vous souhaitez utiliser DATETIME2.

Voici un exemple de conversion d'une chaîne datetimeen datetime2, puis en ajoutant 1 milliseconde, et enfin, en reconvertissant en chaîne.

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
la source