Bonjour à tous,
J'ai eu une certaine confusion pendant un certain temps avec essentiellement un plancher de type SQL DateTime utilisant T-SQL. Essentiellement, je veux prendre une valeur DateTime de disons 2008-12-1 14:30:12 et le faire 2008-12-1 00:00:00. Beaucoup de requêtes que nous exécutons pour les rapports utilisent une valeur de date dans la clause WHERE, mais j'ai soit une valeur de date de début et de fin d'un jour et j'utilise un BETWEEN, soit je trouve une autre méthode.
Actuellement, j'utilise ce qui suit: WHERE CAST(CONVERT(VARCHAR, [tstamp], 102) AS DATETIME) = @dateParam
Cependant, cela semble un peu maladroit. J'espérais qu'il y aurait quelque chose de plus simple comme CAST([tstamp] AS DATE)
Certains endroits en ligne recommandent d'utiliser la fonction DATEPART (), mais je me retrouve avec quelque chose comme ceci:
WHERE DATEPART(year, [tstamp]) = DATEPART(year, @dateParam)
AND DATEPART(month, [tstamp]) = DATEPART(month, @dateParam)
AND DATEPART(day, [tstamp]) = DATEPART(day, @dateParam)
Peut-être que je suis trop préoccupé par quelque chose de petit et si oui, faites-le moi savoir. Je veux juste m'assurer que ce que j'écris est aussi efficace que possible. Je veux éliminer tous les maillons faibles.
Aucune suggestion?
Merci,
C
Merci à tous pour les excellents commentaires. Beaucoup d'informations utiles. Je vais changer nos fonctions pour éliminer la fonction sur le côté gauche de l'opérateur. Bien que la plupart de nos colonnes de date n'utilisent pas d'index, c'est probablement toujours une meilleure pratique.
c'est très mauvais pour les performances, jetez un oeil à Seulement dans une base de données, vous pouvez obtenir une amélioration de 1000% + en changeant quelques lignes de code
les fonctions sur le côté gauche de l'opérateur sont mauvaises
voici ce que tu dois faire
declare @d datetime
select @d = '2008-12-1 14:30:12'
where tstamp >= dateadd(dd, datediff(dd, 0, @d)+0, 0)
and tstamp < dateadd(dd, datediff(dd, 0, @d)+1, 0)
Exécutez ceci pour voir ce qu'il fait
select dateadd(dd, datediff(dd, 0, getdate())+1, 0)
select dateadd(dd, datediff(dd, 0, getdate())+0, 0)
Si vous utilisez SQL Server 2008, il est maintenant intégré, voyez ceci dans livres en ligne
CAST(GETDATE() AS date)
Les fonctions Date publiées par d'autres sont le moyen le plus correct de gérer cela.
Cependant, c'est drôle que vous mentionniez le terme "étage", car il y a un petit hack qui s'exécutera un peu plus vite:
CAST(FLOOR(CAST(@dateParam AS float)) AS DateTime)
CONVERT(date, GETDATE())
et CONVERT(time, GETDATE())
fonctionne dans SQL Server 2008. Je ne suis pas sûr de 2005.
Que dis-tu de ça?
SELECT DATEADD(dd, DATEDIFF(dd,0,GETDATE()), 0)
DATEADD(d, 0, DATEDIFF(d, 0, [tstamp]))
Edit: Bien que cela supprime la partie temporelle de votre datetime, cela rendra également la condition non SARGable . Si cela est important pour cette requête, une vue indexée ou une clause entre est plus appropriée.
Oui, T-SQL peut parfois sembler extrêmement primitif, et ce sont des choses comme celles-ci qui me poussent souvent à faire une grande partie de ma logique dans le langage de mon choix (comme C #).
Cependant, lorsque vous devez absolument faire certaines de ces choses en SQL pour des raisons de performances, alors votre meilleur pari est de créer des fonctions pour héberger ces "algorithmes".
Jetez un œil à cet article. Il offre plusieurs fonctions SQL pratiques dans ce sens qui, je pense, vous aideront.
http://weblogs.sqlteam.com/jeffs/archive/2007/01/02/56079.aspx
Attention ici, si vous utilisez quelque chose sur les lignes de WHERE CAST(CONVERT(VARCHAR, [tstamp], 102) AS DATETIME) = @dateParam
cela forcera un scan sur la table et aucun index ne sera utilisé pour cette partie.
Une manière beaucoup plus propre de procéder consiste à définir une colonne calculée
create table #t (
d datetime,
d2 as
cast (datepart(year,d) as varchar(4)) + '-' +
right('0' + cast (datepart(month,d) as varchar(2)),2) + '-' +
right('0' + cast (datepart(day,d) as varchar(2)),2)
)
-- notice a lot of care need to be taken to ensure the format is comparable. (zero padding)
insert #t
values (getdate())
create index idx on #t(d2)
select d2, count(d2) from #t
where d2 between '2008-01-01' and '2009-01-22'
group by d2
-- index seek is used
De cette façon, vous pouvez vérifier directement la colonne d2 et un index sera utilisé et vous n'aurez pas à vous occuper des conversions.
Vous pouvez également utiliser
declare @d datetimeselect
@d = '2008-12-1 14:30:12'
where tstamp
BETWEEN dateadd(dd, datediff(dd, 0, @d)+0, 0)
AND dateadd(dd, datediff(dd, 0, @d)+1, 0)
Voici une requête qui retournera tous les résultats dans un intervalle de jours.
DECLARE @startDate DATETIME
DECLARE @endDate DATETIME
SET @startDate = DATEADD(day, -30, GETDATE())
SET @endDate = GETDATE()
SELECT *
FROM table
WHERE dateColumn >= DATEADD(day, DATEDIFF(day, 0, @startDate), 0)
AND dateColumn < DATEADD(day, 1, DATEDIFF(day, 0, @endDate))
FWIW, je fais la même chose que toi depuis des années
CAST(CONVERT(VARCHAR, [tstamp], 102) AS DATETIME) = @dateParam
Il me semble que c'est l'un des meilleurs moyens de réduire le temps en termes de flexibilité, de vitesse et de facilité de lecture. (Désolé). Certaines fonctions UDF comme suggéré peuvent être utiles, mais les UDF peuvent être lents avec des jeux de résultats plus volumineux.