J'ai du mal à déterminer la meilleure façon de comparer les dates dans SQL en fonction du mois et de l'année uniquement.
Nous effectuons des calculs en fonction des dates et puisque la facturation a lieu sur une base mensuelle, la date du mois a causé plus d'obstacles.
Par exemple
DECLARE @date1 DATETIME = CAST('6/15/2014' AS DATETIME),
@date2 DATETIME = CAST('6/14/2014' AS DATETIME)
SELECT * FROM tableName WHERE @date1 <= @date2
L'exemple ci-dessus ne retournerait aucune ligne car @ date1 est supérieur à @ date2. J'aimerais donc trouver un moyen de sortir la journée de l'équation.
De même, la situation suivante me donne du chagrin pour la même raison.
DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME),
@date2 DATETIME = CAST('6/15/2014' AS DATETIME),
@date3 DATETIME = CAST('7/1/2014' AS DATETIME)
SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3
J'ai effectué des conversions en ligne des dates pour dériver le premier jour et le dernier jour du mois pour la date spécifiée.
SELECT *
FROM tableName
WHERE date2 BETWEEN
DATEADD(month, DATEDIFF(month, 0, date1), 0) -- The first day of the month for date1
AND
DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, date2) + 1, 0)) -- The lastday of the month for date3
Il doit y avoir un moyen plus simple de le faire. Aucune suggestion?
Pour gérer les inégalités, telles qu'entre les deux, j'aime convertir la date/l'heure en une représentation YYYYMM, sous forme de chaîne ou d'entier. Pour cet exemple:
DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME),
@date2 DATETIME = CAST('6/15/2014' AS DATETIME),
@date3 DATETIME = CAST('7/1/2014' AS DATETIME);
SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3;
J'écrirais la requête comme suit:
SELECT *
FROM tableName
WHERE year(@date2) * 100 + month(@date2) BETWEEN year(@date1) * 100 + month(@date1) AND
year(@date3) * 100 + month(@date1);
Vous pouvez filtrer le mois et l'année d'une date donnée sur la date actuelle comme suit:
SELECT *
FROM tableName
WHERE month(date2) = month(getdate()) and year(date2) = year(getdate())
Remplacez simplement la méthode GETDATE()
par la date souhaitée.
Tout d'abord, j'utiliserais un format pour les dates sans ambiguïté, comme le standard 'YYYYMMDD'
Et non le '6/15/2014'
Que vous avez utilisé. Le blog d'Aaron Bertrand explique bien mieux que moi les différentes manières dont cela peut mal tourner:
Mauvaises habitudes de lancer: mauvaise gestion des requêtes de date/plage
Pour le problème spécifique, votre dernière requête qui trouve le premier et le dernier jour des mois (pour date1 et date3), est à mon avis sur la bonne voie. Vous n'avez besoin que des premiers jours des mois (premier jour de date1 et premier jour du mois suivant pour date3), si vous évitez le evil BETWEEN
: Qu'ont en commun BETWEEN et le diable?
SELECT *
FROM tableName
WHERE date2 >= DATEADD(month, DATEDIFF(month, '19000101', @date1), '19000101')
AND date2 < DATEADD(month, 1+DATEDIFF(month, '19000101', @date3), '19000101') ;
La requête fonctionne telle quelle, quel que soit le type de données de date2
(DATE
, DATETIME
, DATETIME2
Ou SMALLDATTEIME
).
Point bonus, les index sur date2
Seront ainsi considérés par l'optimiseur.
Amélioration, selon (encore un autre) article de blog d'Aaron, pour éviter un problème d'estimation de la cardinalité lors de l'évaluation des expressions avec DATEDIFF()
:
Surprises et hypothèses de performance: DATEDIFF
SELECT *
FROM tableName
WHERE date2 >= CONVERT(DATE, DATEADD(day, 1 - DAY(@date1), @date1))
AND date2 < DATEADD(month, 1,
CONVERT(DATE, DATEADD(day, 1 - DAY(@date3), @date3))) ;
Vous pouvez utiliser le formatage de votre date comme ceci "aaaaMM", donc seul le mois de la même année sera sélectionné.
SELECT *
FROM tableName
WHERE FORMAT(date_month_bill, 'yyyyMM') < FORMAT(DATEADD(MONTH, -1, GETDATE()), 'yyyyMM')
AND FORMAT(date_month_bill, 'yyyyMM') > FORMAT(DATEADD(MONTH, -3, GETDATE()), 'yyyyMM')