J'ai besoin d'aide pour sélectionner des dates entre la plage de 12 à 9 mois précédente. À titre d'exemple, si aujourd'hui est le 2-22-2017, je dois tirer une plage de dates du 2-1-2016 au 3-31-2016.
Je peux sélectionner toutes les dates des 12 mois précédents en utilisant ceci:
WHERE READDATE >= DATEADD(month, DATEDIFF(month, 0, DATEADD(MONTH,-12,GETDATE())), 0)
AND READDATE <= DATEADD(s,-12,DATEADD(MONTH, DATEDIFF(MONTH,0,GETDATE()),0))
Mais je ne peux pas comprendre comment exclure les dates après les 9 mois précédents me donnant cette fenêtre de 3 mois.
Cela devrait fonctionner:
...
WHERE
-- >= 2016-02-01 00:00:00.000
READDATE >= DATEADD(month, DATEDIFF(month, 0, GETDATE()) - 12, 0)
-- < 2016-04-01 00:00:00.000
READDATE < DATEADD(month, DATEDIFF(month, 0, GETDATE()) - 10, 0)
...
Veuillez noter qu'avec les dates, il est généralement préférable de le comparer de cette façon:
X >= lower bound
AND
X < upper bound
C'est pourquoi je change <= '20160331'
à < '20160401'
. Bien que cela fonctionne bien avec votre échantillon en utilisant ce qui semble être des types de date, il peut donner des résultats incorrects en utilisant des dates avec une partie de temps.
Si vous utilisez SQL Server 2012 ou plus tard, vous pouvez utiliser DATEFROMPARTS
pour vous aider:
WHERE READDATE >= DATEADD(MONTH,-12,DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()),1))
AND READDATE < DATEADD(MONTH, -9,DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()),1))
Les modifications mineures rendront également ce travail pour les quartiers calendaires à la place si le roulement de trois mois.
Avant 2012 DATEFROMPARTS
n'existait pas cependant pour ce cas, il existe un piratage facile avec la coulée de cordes:
WHERE READDATE >= DATEADD(MONTH,-12,CAST(CONVERT(CHAR(7),GETDATE(),121) AS DATE))
AND READDATE < DATEADD(MONTH, -9,CAST(CONVERT(CHAR(7),GETDATE(),121) AS DATE))
Je me méfie d'utiliser DATEADD
et DATEDIFF
dans la clause WHERE
en raison de l'impact potentiel sur les estimations:
En outre, si vous vous souciez de la performance, j'ai prouvé que l'utilisation de choses comme FORMAT()
ou CAST/CONVERT()
à une chaîne afin de dépasser le temps d'un datetime
est sous- optimal:
Et puisque vous n'êtes pas sur SQL Server 2012 ou plus grand, vous ne pouvez pas utiliser DATEFROMPARTS()
, ce qui est probablement le moyen le plus propre de le faire. Mais il reste encore une voie bien rangée pour avoir le début du mois en cours (d'abord, soustrayez aujourd'hui, puis convertir en date
) et de là, il est trivial pour soustraire une année, puis 9 mois et Construire une clause O WHERE
:
DECLARE @ThisMonth date = DATEADD(DAY, 1-DAY(GETDATE()), GETDATE());
SELECT ... FROM dbo.tablename ...
WHERE READDATE >= DATEADD(YEAR, -1, @ThisMonth)
AND READDATE < DATEADD(MONTH, -9, @ThisMonth);
Je n'utiliserais jamais >=
et <=
Pour une requête de plage de date. Cela équivaut à BETWEEN
et peut conduire à toutes sortes d'inexactitudes , comme de confiance que les données ne pouvaient être enregistrées que jusqu'à 12 secondes avant minuit (?). N'essayez pas de trouver des données au ou avant la "fin" d'une période - la façon dont vous voulez penser à cela est que vous voulez juste tout avant le début du suivant période.
Une autre lecture sur les requêtes de date/gamme:
Vous pouvez vérifier cette solution, cela vous donnera toutes les dates entre la plage sélectionnée.
DECLARE @startdate DATETIME
,@enddate DATETIME
SET @startdate = '1/1/2012'
SET @enddate = '1/15/2012'
;WITH cte
AS (
SELECT @startdate DateVal
UNION ALL
SELECT DateVal + 1
FROM cte
WHERE DateVal + 1 <= @enddate
)
SELECT c.DateVal, COALESCE(sum(quantity),0)
FROM cte c
LEFT JOIN YourTable t ON c.DateVal = t.ProductionDate
GROUP BY c.DateVal