web-dev-qa-db-fra.com

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

J'ai fait une convert(varchar,datefield,112) sur chaque champ de date que j'utilise dans les requêtes 'entre' dans SQL Server pour m'assurer que je ne comptabilise que les dates et n'en manque aucune en fonction de la partie heure de champs datetime.

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

Quelle est la méthode optimale et indexable de faire quelque chose comme ceci:

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

La conversion de types numériques en valeurs de chaîne (un type de boxe) n'est pas la méthode la plus performante pour faire ce que vous recherchez. Ce n'est pas vraiment indexable, car le type de colonne réel est la date et l'heure.

Si vous recherchez la meilleure façon de rechercher des dates, votre exemple est exact, mais vous voudrez peut-être prendre en compte la différence de précision de 3 ms dans MSSQL. Cela peut signifier que les enregistrements d'une journée peuvent apparaître dans le résultat d'une autre journée.

Cette

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

Devrait être ceci

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

La meilleure façon de supprimer la partie temporelle d'un champ datetime est d'utiliser les fonctions datiff et dateadd.

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

Cela profite du fait que SQL Server stocke les dates sous la forme de deux entiers, l'un représentant le nombre de jours depuis le jour "0" 1er janvier 1900) et le second qui représente le nombre de --- (( ticks (chaque tick est d'environ 3,33 ms) depuis minuit (pour l'heure) *.

la formule ci-dessus doit simplement lire le premier entier. Aucune conversion ou traitement n'est requis, il est donc extrêmement rapide.

Pour que vos requêtes utilisent un index ... utilisez d'abord cette formule sur les paramètres de filtrage d'entrée, ou sur "l'autre" du signe égal du champ date et heure des tables, afin que l'optimiseur de requête n'ait pas à exécuter le calcul sur chaque champ datetime de la table pour déterminer quelles lignes satisfont le prédicat de filtre. Cela rend votre argument de recherche "capable de SARG" (ARGument de recherche)

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

plutôt que

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

* REMARQUE. En interne, le deuxième entier (la partie temporelle) stocke les ticks. Dans une journée, il y a 24 x 60 X 60 X 300 = 25 920 000 ticks (par hasard juste en dessous de la valeur maximale qu'un entier 32 bits peut contenir). Cependant, vous n'avez pas à vous en préoccuper lors de la modification arithmétique d'un datetime ... Lorsque vous ajoutez ou soustrayez des valeurs des datetimes, vous pouvez traiter la valeur comme une fraction comme si elle était exactement égale à la partie fractionnaire d'une journée, comme si le la valeur datetime complète était un nombre à virgule flottante composé d'une partie entière représentant la date et la partie fractionnaire représentant l'heure). c'est à dire.,

`Declare @Dt DateTime  Set @Dt = getdate()  
 Set @Dt = @Dt + 1.0/24  -- Adds one hour  
 Select @Dt  
 Set @Dt = @Dt - .25 -- Moves back 6 hours  
 Select @Dt`
66
Charles Bretana

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), donc vous inclurez toutes les heures pour le 01/08, et toutes les heures pour le 15/08, et tout ce qui est exactement le 16/08/2008 00:00:00

2
Kieveli

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.

1
devio

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)
0
Mladen Mihajlovic