web-dev-qa-db-fra.com

Comment ajouter 1 millisecondes à une chaîne datetime?

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.

15
Racer SQL

Datetime n'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 (par exemple datetime2).

Documentation

Devis important:

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

33
Forrest

La fonction DateAdd est ce que vous recherchez.

Utilisez millisecond comme premier paramètre de la fonction pour lui indiquer que vous ajoutez des millisecondes. Utilisez ensuite 1 comme deuxième paramètre, pour 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 souligne dans une autre réponse, le type de données datetime 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.

13
Doug Deden

@ 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 a Common Table Expression (modifier 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
13
BlueGI

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)

enter image description here

Les différences entre datetime et datetime2 sont bien expliqués ici .

Pour cet exercice, je crée une table temporaire à des fins de test et je la remplis avec 999 random dates de 01-jan-2019 et aujourd'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)

enter image description here

4
Marcello Miorelli

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 datetime en 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'
                )
            )
        )
2