28 votes

Convertir les champs datetime du serveur SQL pour comparer les parties de date uniquement, avec des recherches indexées

J'ai fait un convert(varchar,datefield,112) sur chaque champ date que j'utilise dans "entre" les requêtes dans SQL server pour s'assurer que je ne fais que de la comptabilité pour les dates et ne manque pas de base sur le temps de les champs datetime.

Maintenant, j'entends que les convertis ne sont pas indexables et qu'il existe de meilleures méthodes, dans SQL Server 2005, à comparer à la partie de la date de datetimes dans une requête pour déterminer si les dates sont comprises dans une gamme.

Quel est le meilleur, indexable, la méthode de faire quelque chose comme ceci:

select * from appointments
where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'

67voto

Charles Bretana Points 59899

La meilleure façon de bande de l'époque partie d'un champ de date / heure est à l'aide de datediff et dateadd fonctions.

   DateAdd(day, datediff(day,0, MydateValue), 0)

Cela prend un atout du fait que SQL Server stocke les dates que deux entiers, l'un représentant le nombre de jours depuis le premier jour "0" - (1 janv 1900), et le second, qui représente le nombre de tiques (chaque tick est environ 3,33 ms) depuis minuit (pour le moment) *.

la formule ci-dessus n'a tout simplement de ne lire que le premier entier. Il n'y a pas de conversion ou de transformation requis, de sorte qu'il est extrêmement rapide.

Pour rendre vos requêtes utiliser un index... utilisation de cette formule sur le filtrage des entrées de paramètres, ou sur "l'autre" côté du signe égal de l'tables date heure terrain, afin que l'optimiseur de requête n'a pas à exécuter le calcul sur chaque champ de la table pour déterminer les lignes qui satisfont le prédicat de filtre. Cela permet à votre recherche "argument de SARG-mesure" (ARGument de Recherche)

Where MyDateTimeColumn > DateAdd(day, 
      datediff(day,0, @MydateParameter), 0)    -- SARG-able

plutôt que de

Where DateAdd(day, datediff(day,0, 
      MyDateTimeColumn ), 0) > MydateParameter -- Not SARG-able
  • REMARQUE. En interne, le deuxième entier (le temps) stocke les tiques. Dans une journée il y a 24 x 60 X 60 X 300 = 25,920,000 tiques (par hasard juste au-dessous de la valeur maximale d'un entier de 32 bits peut contenir). Cependant, vous ne devez pas vous inquiéter à ce sujet lors de l'arithmétique de la modification d'un datetime... Lors de l'ajout ou la soustraction des valeurs de datetimes vous pouvez traiter la valeur que d'une fraction comme si c'était exactement égale à la fraction de fraction de jour, comme si le datetime complet de la valeur est un nombre à virgule flottante composée d'une partie entière représentant la date et la partie fractionnaire représentant le temps). c'est à dire,

    Declare @Dt DateTime Set @Dt = getdate()

5voto

StingyJack Points 10956

La conversion de types numériques de la chaîne de valeurs (un type de Boxe) n'est pas la meilleure méthode de faire ce que vous êtes recherche pour. Ce n'est pas vraiment sur l'indice-mesure, car la colonne est de type date temps.

Si vous êtes à la recherche de la meilleure façon de requête pour les dates, votre exemple est bon, mais vous voudrez peut-être prendre en compte les 3 ms précision différence de MSSQL. Cela peut signifier que les enregistrements à partir d'un jour peuvent apparaître dans un autre jour que le résultat de l'.

Cette

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'

Doit être ce

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<='08-14-2008 23:59:59.996'

2voto

Kieveli Points 7162

C'est correct - faire la conversion exécutera la conversion pour chaque ligne interrogée. Il est préférable de laisser les colonnes de date en tant que dates et de passer vos clauses where en tant que dates:

 select * from appointments where appointmentdate between 
'08/01/2008' AND '08/16/2008'
 

Remarque: Le fait de laisser l'heure signifie minuit (00: 00.000), vous inclurez donc toutes les heures du 08/01 et toutes les heures du 15/08, et tout ce qui est exactement le 16/08/2008 00:00:00

1voto

devio Points 22981

Demandez à une colonne persistante calculée de calculer l'expression dont vous avez besoin. Si les colonnes sont calculées et persistantes, elles peuvent également être indexées.

0voto

Mladen Mihajlovic Points 2476

Il y a aussi la manière décrite sur http://www.stillnetstudios.com/comparing-dates-without-times-in-sql-server/

 SELECT CAST(FLOOR(CAST( getdate() AS float )) AS datetime)
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X