web-dev-qa-db-fra.com

Meilleure approche pour supprimer une partie de l'heure de datetime dans SQL Server

Quelle méthode offre les meilleures performances lors de la suppression de la partie heure d'un champ datetime dans SQL Server?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

ou

b) select cast(convert(char(11), getdate(), 113) as datetime)

La deuxième méthode envoie quelques octets de plus dans les deux sens mais cela n’est peut-être pas aussi important que la vitesse de la conversion.

Les deux semblent également très rapides, mais il pourrait y avoir une différence de vitesse quand on traite avec des centaines de milliers ou plus de lignes?

Aussi, est-il possible qu'il existe des méthodes encore meilleures pour se débarrasser de la partie heure d'un datetime en SQL?

492
Stephen Perelson

Strictement, la méthode a est la moins gourmande en ressources:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Il a été prouvé qu’il nécessitait moins de ressources processeur pour une durée totale identique, un million de lignes sur une personne disposant de beaucoup trop de temps: Le moyen le plus efficace dans SQL Server d’obtenir la date à partir de la date + heure?

J'ai vu un test similaire ailleurs avec des résultats similaires.

Je préfère le DATEADD/DATEDIFF parce que:

Edition, octobre 2011

Pour SQL Server 2008+, vous pouvez CAST to date. Ou utilisez simplement date afin de ne pas perdre de temps.

Edit, Jan 2012

Voici un exemple concret de souplesse: nécessité de calculer par date et heure arrondies sur le serveur SQL

Edit, mai 2012

N'utilisez pas ceci dans les clauses WHERE et autres sans y penser: ajouter une fonction ou CAST à une colonne invalide l'utilisation de l'index. Voir le numéro 2 ici: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/

Maintenant, cela contient un exemple de versions ultérieures de l'optimiseur SQL Server qui gèrent correctement CAST, mais en général , ce sera une mauvaise idée ...

Éditer, septembre 2018, pour datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2Epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2Epoch, @datetime2value), @datetime2Epoch)
534
gbn

Dans SQL Server 2008, vous pouvez utiliser:

CONVERT(DATE, getdate(), 101)
59
Anto Raja Prakash

Bien sûr, c’est un vieux fil, mais il faut le compléter.

A partir de SQL 2008, vous pouvez utiliser le type de données DATE pour effectuer simplement:

SELECT CONVERT(DATE,GETDATE())
44
Arjan Fraaij
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)

... est pas une bonne solution, selon les commentaires ci-dessous.

Je voudrais supprimer cette réponse, mais je la laisserai ici comme contre-exemple car je pense que l'explication des commentateurs sur explique pourquoi ce n'est pas une bonne idée est toujours utile.

21
Gary McGill

Dans SQL Server 2008, il existe un type de données DATE (également un type de données TIME).

CAST(GetDate() as DATE)

ou

declare @Dt as DATE = GetDate()
15
Metaphor

Voici encore une autre réponse, d'un autre question en double:

SELECT CAST(CAST(getutcdate() - 0.50000004 AS int) AS datetime) 

Cette méthode de nombre magique effectue légèrement plus vite que la méthode DATEADD. (Cela ressemble à ~ 10%)

Le temps CPU sur plusieurs tours d'un million d'enregistrements:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

Mais notez que ces chiffres ne sont peut-être pas pertinents car ils sont déjà TRÈS rapides. À moins d’avoir 100 000 enregistrements ou plus, je ne pouvais même pas obtenir le temps de calcul du processeur au-dessus de zéro.

Étant donné que DateAdd est conçu à cet effet et qu'il est plus robuste, utilisez plutôt DateAdd.

8
Jeff Meatball Yang
SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)
5
Byju

J'aime vraiment:

[date] = CONVERT(VARCHAR(10), GETDATE(), 120)

Le code de format 120 contraindra la date à la norme ISO 8601:

'YYYY-MM-DD' or '2017-01-09'

Super facile à utiliser dans dplyr (R) et pandas (Python)!

4
emehex

IL FAUT SE MÉFIER!

Les méthodes a) et b) n'ont PAS toujours la même sortie!

select DATEADD(dd, DATEDIFF(dd, 0, '2013-12-31 23:59:59.999'), 0)

Sortie: 2014-01-01 00:00:00.000

select cast(convert(char(11), '2013-12-31 23:59:59.999', 113) as datetime)

Sortie: 2013-12-31 00:00:00.000

(Testé sur MS SQL Server 2005 et 2008 R2)

EDIT: Selon le commentaire d'Adam, cela ne peut pas arriver si vous lisez la valeur de date de la table, mais cela peut arriver si vous fournissez votre valeur de date sous forme littérale (exemple: en tant que paramètre d'une procédure stockée appelée via ADO.NET).

3
broslav
CAST(round(cast(getdate()as real),0,1) AS datetime)

Cette méthode n'utilise pas de fonction de chaîne. Date est fondamentalement un type de données réel avec des chiffres avant la virgule représentant une fraction de jour.

je suppose que cela sera plus rapide que beaucoup.

2

Voir cette question:
Comment puis-je tronquer une date/heure dans SQL Server?

Quoi que vous fassiez, n'utilisez pas la méthode des chaînes de caractères . C'est à peu près la pire façon de le faire.

2
Joel Coehoorn

sélectionnez CONVERT (char (10), GetDate (), 126)

2
Diego

Décollez le temps sur les inserts/mises à jour en premier lieu. En ce qui concerne la conversion à la volée, rien ne peut battre une fonction définie par l'utilisateur en matière de maintenance:

select date_only(dd)

L'implémentation de date_only peut être ce que vous voulez - maintenant, elle est abstraite et le code d'appel est beaucoup plus propre.

2
Anton Gogolev

Déjà répondu mais mal jette ça aussi là-bas ... cela se forme bien aussi mais cela fonctionne en jetant la décimale (qui stocke le temps) du flotteur et en ne renvoyant que la partie entière (qui est la date)

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

la deuxième fois que j'ai trouvé cette solution ... j'ai enlevé ce code

2
Carter Cole

Pour moi, le code ci-dessous est toujours gagnant:

SELECT CONVERT(DATETIME, FLOOR(CONVERT(FLOAT,GETDATE())));
2
user1920017

Ici, j'ai créé une fonction permettant de supprimer certaines parties d'un datetime pour SQL Server. Usage:

  • Le premier paramètre est la date et l'heure à supprimer.
  • Le deuxième paramètre est un caractère:
    • s: arrondit aux secondes; supprime les millisecondes
    • m: arrondit aux minutes; supprime les secondes et millisecondes
    • h: arrondit aux heures; supprime les minutes, les secondes et les millisecondes.
    • d: arrondit aux jours; supprime les heures, les minutes, les secondes et les millisecondes.
  • Renvoie la nouvelle date et heure

create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end

1
Max Vargas

Je pense que tu veux dire cast(floor(cast(getdate()as float))as datetime)

réel est seulement 32 bits, et pourrait perdre certaines informations

C'est le plus rapide cast(cast(getdate()+x-0.5 as int)as datetime)

... bien que seulement 10% plus rapide(about 0.49 microseconds CPU vs. 0.58)

Cela a été recommandé et prend le même temps dans mon test en ce moment: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

En SQL 2008, la fonction CLR SQL est environ 5 fois plus rapide que l'utilisation d'une fonction SQL: 1,35 microsecondes contre 6,5 microsections, ce qui indique une surcharge d'appels de fonction beaucoup moins importante pour une fonction CLR SQL par rapport à un simple fichier UDF SQL.

En SQL 2005, la fonction SQL CLR est 16 fois plus rapide, selon mes tests, par rapport à cette fonction lente:

create function dateonly (  @dt datetime )
returns datetime
as
begin
return cast(floor(cast(@dt as float))as int)
end
1
Aaron West

Juste au cas où quelqu'un chercherait ici une version de Sybase puisque plusieurs des versions ci-dessus ne fonctionnaient pas

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • Testé dans I SQL v11 sous Adaptive Server 15.7
1
Alan

Que diriez-vous de select cast(cast my_datetime_field as date) as datetime)? Il en résulte la même date, avec l'heure définie sur 00:00, mais évite toute conversion en texte et évite également tout arrondi numérique explicite.

1
Dr. Drew

Je pense que si vous vous en tenez strictement à TSQL, c’est le moyen le plus rapide de tronquer le temps:

 select convert(datetime,convert(int,convert(float,[Modified])))

J'ai trouvé cette méthode de troncature environ 5% plus rapide que la méthode DateAdd. Et cela peut être facilement modifié pour arrondir au jour le plus proche comme ceci:

select convert(datetime,ROUND(convert(float,[Modified]),0))
1
Jamie G

Si possible, j'aime utiliser les fonctions CLR pour des tâches spéciales comme celle-ci.

Dans ce cas:

[Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime DateOnly(SqlDateTime input)
    {
        if (!input.IsNull)
        {
            SqlDateTime dt = new SqlDateTime(input.Value.Year, input.Value.Month, input.Value.Day, 0, 0, 0);

            return dt;
        }
        else
            return SqlDateTime.Null;
    }
0
tjeuten

Personnellement, j’utilise presque toujours fonctions définies par l’utilisateur pour cela s’il s’agit de SQL Server 2005 (ou d'une version antérieure), il convient toutefois de noter qu'il existe des inconvénients spécifiques à l'utilisation des fonctions définies par l'utilisateur, en particulier si elles sont appliquées. to WHERE (voir ci-dessous et les commentaires sur cette réponse pour plus de détails). Si vous utilisez SQL Server 2008 (ou supérieur) - voir ci-dessous.

En fait, pour la plupart des bases de données que je crée, j'ajoute ces fichiers UDF dès le début, car je sais qu'il y a 99% de chances que j'en aie besoin tôt ou tard.

J'en crée un pour "date seulement" et "heure seulement" (bien que celui "date seulement" soit de loin le plus utilisé des deux).

Voici quelques liens vers divers types de fonctions définies par l'utilisateur:

Fonctions essentielles de SQL Server Date, Time et DateTime
Fonction Get Date Only

Ce dernier lien montre pas moins de 3 façons différentes d’obtenir la date comme une partie d’un champ date-heure et mentionne le pour et le contre de chaque approche.

Si vous utilisez un fichier UDF, notez que vous devez éviter de l’utiliser dans le cadre d’une clause WHERE dans une requête, car cela entraverait considérablement les performances de la requête. La raison principale en est que l'utilisation d'un fichier UDF dans une clause WHERE convertit cette clause en non-sargable , ce qui signifie que SQL Server ne peut plus utiliser d'index avec cette clause afin d'améliorer la vitesse de exécution de la requête. En ce qui concerne ma propre utilisation des fonctions définies par l'utilisateur, j'utiliserai fréquemment la colonne de date "brute" dans la clause WHERE, mais j'appliquerai la fonction UDF à la colonne SELECTed. De cette manière, la fonction utilisateur n'est appliquée qu'à l'ensemble de résultats filtré et non à chaque ligne de la table faisant partie du filtre.

Bien sûr, la meilleure approche absolue consiste à utiliser SQL Server 2008 (ou une version ultérieure) et à séparer vos dates et heures =, étant donné que le moteur de base de données SQL Server fournit alors en natif les composants individuels de date et d’heure, et peut les interroger de manière efficace indépendamment sans avoir recours à une fonction utilisateur ou à un autre mécanisme pour extraire la partie date ou heure d’un type de date et heure composite.

0
CraigTP