Il existe différentes fonctions que vous pouvez utiliser pour y parvenir, comme DATEPART et DATETIFF. Cependant, le vrai problème n'est pas comment exprimer la condition de StartDate ou EndDate tombant sur le mois donné, mais comment faire ceci d'une manière qui rend la requête efficace. En d'autres termes, comment exprimer cela d'une manière SARGable. Dans le cas où vous recherchez une petite table de changement, n'importe quoi sous 10k pages, alors cela ne fait pas tellement de différence, un balayage complet serait probablement parfaitement acceptable. La vraie question est de savoir si la ou les tables ont une taille significative et si une analyse complète est inacceptable.
Si vous ne possédez aucun index sur les colonnes StartDate ou EndDate, cela ne fait aucune différence, le critère n'est pas consultable et la requête analyse quand même la totalité de la table. Cependant, s'il existe des index sur StartDate et EndDate, la façon dont vous exprimez la condition fait toute la différence. La partie critique pour les index DATETIME est que vous devez exprimer la recherche comme une plage de dates exacte. L'expression de la condition en tant que fonction en fonction du champ DATETIME rendra la condition impossible à rechercher, ce qui entraînera une analyse complète de la table. Donc, cette connaissance se rendre à la manière correcte la recherche d'une plage de dates:
select ... from table
where StartDate between '20091101' and '20091201'
or EndDate between '20091101' and '20091201';
Cela peut aussi être exprimée comme suit:
select ... from table
where StartDate between '20091101' and '20091201'
union all
select ... from table
where EndDate between '20091101' and '20091201'
and StartDate not between '20091101' and '20091201';
Quelle requête fonctionne mieux dépend d'un certain nombre de facteurs, comme la taille de la table et les statistiques des données réelles dans le tableau.
Cependant, vous voulez le mois de novembre de année, que cette requête ne vous donne pas. La solution à ce problème est contre tous les instincts d'un programmeur: coder dur les années pertinentes. La plupart du temps les tables ont un petit nombre d'années de toute façon, quelque chose dans la gamme de 4-5 années de données passées et de planifier 3-4 ans plus jusqu'à ce que le système sera révisé:
select ... from table
where StartDate between '20051101' and '20051201'
or EndDate between '20051101' and '20051201'
union all
select ... from table
where StartDate between '20061101' and '20061201'
or EndDate between '20061101' and '20061201'
union all
...
select ... from table
where StartDate between '20151101' and '20151201'
or EndDate between '20151101' and '20151201';
Il y a 12 mois en une année, écrivez 12 procédures distinctes. Est-ce que ça a l'air fou? C'est sûr, mais c'est la chose optimale de la perspective du compilateur de requêtes SQL et de l'optimiseur. Comment peut-on maintenir un tel code? 12 procédure distincte, avec une requête qui se répète 10 fois (20 fois si vous utilisez l'UNION entre StartDate et EndDate pour supprimer l'OR), 120 répétitions de code, doit être être non-sens. En fait, ce n'est pas le cas. Utilisez la génération de code pour créer les procédures, comme XML/XSLT, de sorte que vous pouvez facilement le modifier et le maintenir. Est-ce que le client doit connaître les 12 procédures et appeler la bonne? Bien sûr que non, il appelle une procédure wrapper qui discrimine l'argument @Month pour appeler le bon.
Je reconnais que toute personne qui se penchera sur le système après les faits croira probablement que cette requête a été écrite par une bande de singes ivres. Pourtant, quelque part entre le reniflage de paramètres, l'indice SARGability et les caprices de SQL DATETIME, il en résulte que c'est aujourd'hui l'état de l'art lorsqu'il s'agit de rechercher des intervalles de calendrier.
Oh, et si la requête frappe le Index Tipping Point il rendra l'ensemble de l'argument muet de toute façon ...
Mise à jour
BTW il y a aussi un moyen pas cher si vous êtes prêt à sacrifier un peu d'espace de stockage: deux persista colonnes calculées sur StartMonth AS DATEPART(month, StartDate)
et EndDate AS DATEPART(month, EndDate)
, et l'index sur chaque et requête WHERE StartMonth = @Month OR EndMonth = @Month
(ou encore UNION entre deux requêtes une pour Démarrer un pour Fin, pour supprimer le OU).
Il semble que vous ayez vraiment besoin d'un certain mois au cours d'une année donnée, où le mois croise la période entre deux dates. La façon dont vous l'avez dit donne l'impression que seules les dates de début et de fin doivent avoir le mois. – Chris
Qu'est-ce que Chris a dit - étant donné l'entrée ci-dessus quels enregistrements voulez-vous sélectionner? – Murph
Tous les 5, car ils incluent ou chevauchent le mois de novembre. L'année n'a pas d'importance. La plage de dates doit inclure au moins un jour en novembre. –