web-dev-qa-db-fra.com

Date MS SQL uniquement sans heure

Question

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

Solution

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.

38
regex

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)
35
SQLMenace

Si vous utilisez SQL Server 2008, il est maintenant intégré, voyez ceci dans livres en ligne

CAST(GETDATE() AS date)

81
JoshBerke

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)
9
Joel Coehoorn

CONVERT(date, GETDATE()) et CONVERT(time, GETDATE()) fonctionne dans SQL Server 2008. Je ne suis pas sûr de 2005.

7
AaronS

Que dis-tu de ça?

SELECT DATEADD(dd, DATEDIFF(dd,0,GETDATE()), 0)
5
Sameer
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.

1
Mark Brackett

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

1
Lusid

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.

1
Sam Saffron

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)
0
Xander

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))
0
Rob Boek

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.

0
Booji Boy