2008-12-26 8 views
0

J'ai une table dans SQL Server 2005 qui a trois colonnes:Comment table de requête SQL Server basé sur une date précise

id (int), 
message (text), 
timestamp (datetime) 

Il y a un index sur l'horodatage et id.

Je suis intéressé à faire une requête qui récupère tous les messages pour une date donnée, disons '12/20/2008 '. Cependant, je sais que faire simplement où timestamp = '12/20/2008 'ne me donnera pas le bon résultat parce que le champ est un champ datetime.

Quelqu'un a recommandé d'utiliser la fonction DATEPART et d'extraire l'année, le mois et le jour de l'horodatage et de vérifier qu'ils sont égaux à 2008, 12 et 20, respectivement. Il semble que cela n'utiliserait pas l'index que j'ai sur l'horodatage et finirait par faire un scan complet de la table.

Alors, quelle est la meilleure façon de construire ma requête afin que je profite de l'index que j'ai créé?

Répondre

1
-- avoid re-calculating @MyDate +1 for every row 
DECLARE @NextDay DateTime 
Set @NextDay = @MyDate + 1 

SELECT 
    -- ... 
WHERE [timestamp] >= @MyDate AND [timestamp] < @NextDay 
+0

Le serveur SQL ne serait-il pas assez intelligent pour comprendre qu'il n'a besoin que de calculer @MyDate + 1 une fois pour l'instruction? – erikkallen

+0

Probablement. Je sais pertinemment qu'il ne le fera pas pour getdate(), cependant. Bien sûr, c'est un appel de fonction, ce qui est un peu différent. Mais je suis paranoïaque à propos de tout ce dont je n'ai pas besoin dans une clause where. –

+0

cela ne fonctionnera pas si @MyDate a une partie temporelle. Pour corriger cette utilisation: Où [horodatage]> = DateAdd (jour, DateDiff (jour, 0, @Date), 0) Et [horodatage]

0

L'instruction BETWEEN peut vous aider.

SELECT * 
FROM MyTable 
WHERE TimeStamp BETWEEN @Start AND @End; 

Démarrer devrait être quelque chose comme 00h01 pour le jour où vous voulez que les messages pour, et à la fin serait comme 23h59 pour la fin du même jour.

+0

La chose 12: 00: 00.000 vs 11: 59: 59.999 rend plus simple dans mon esprit d'utiliser deux opérateurs de comparaison et les opérateurs appropriés, comme je l'ai montré plus tôt. –

+0

@Joel - Entre fait les mêmes choses que vos opérateurs mais est plus facile à lire (au moins OMI). –

+0

Non, ce n'est pas le cas. J'ai créé une autre réponse à démontrer, car il n'y a pas de place ici. –

2

L'utilisation de deux variables datetime a toujours fonctionné infailliblement dans mon expérience. La question de la résolution semble très improbable. Le fait important à retenir, cependant, est qu'une plage (de n'importe quel type) inclut les deux points d'extrémité. Vous ne pouvez donc pas tester BETWEEN à deux dates, car cela inclura les deux. Plutôt utiliser quelque chose comme

datefield> = @StartDate ET datefield < @EndDate

The Manual.

C'mon gens - la documentation de ce n'est pas que difficile à trouver. : D

0

ENTRE ne fait PAS> =, <. Il fait> =, < =, car ce code prouve:

declare @low datetime 
declare @high datetime 
set @low = getdate() 
set @high = @low+1 

select case when @low between @low and @high then 1 else 0 end, 
    case when @high between @low and @high then 1 else 0 end 

Le résultat sera 1,1, montrant que les = est appliqué aux deux limites.

0

En supposant @Date est une valeur datetime pour tout datetime le jour où vous souhaitez que tous les messages pour, utilisez ce

Where [timestamp] >= DateAdd(day, DateDiff(day, 0, @Date), 0) 
    And [timestamp] < DateAdd(day, DateDiff(day, 0, @Date), 1) 

Ceci est beaucoup plus rapide que d'utiliser un CAST, sans oublier que lors de l'utilisation de CAST sur datetimes, si vous lancez une valeur datetime qui est après midi à un entier,

Declare @MyDate as Datetime 
Set @MyDate = '12/25/2008 12:01:00' 
Declare @IntVal Integer 
Set @IntVal = Cast(@MyDate as Integer) 
Select Cast(@IntVal as DateTime) 

il va arrondir à l'entier représentant la date de TNE lendemain. Le script ci-dessus va sortir 12/26/2008

Questions connexes