2010-07-07 22 views
1

J'ai une table appelée Périodes qui ressemble à ceciBesoin d'aide avec une plage de dates de sélection de requête SQL à partir d'une table des quartiers d'époque

PeriodID | PeriodYear | PériodeQuartier

7 | 2009 | 1

8 | 2009 | 2

9 | 2009 | 3

10 | 2009 | 4

11 | 2010 | 1

12 | 2010 | 2

Chaque ligne du tableau représente 1 des 4 trimestres de l'année (comme les trimestres scolaires). Par exemple. La première ligne représente la période 1 de 2009 (c.-à-d. La période du 1er janvier 2009 au 31 mars 2009.

Maintenant, je dois écrire une requête qui sélectionne les lignes/périodes du tableau ci-dessus, où la période se situe entre 2 plages de dates , selon le pseudo-code.

select * 
from Periods 
where Period is between @startDate and @endDate 

suite à la requête sera utilisée à l'intérieur d'une fonction table appelée valeur dbo.GetPeriodsFromDateRange et @StartDate et @EndDate sont des paramètres à la fonction.

Je suis coincé et ne peut pas comprendre comment le faire.S'il vous plaît aider.Cela s'applique à T-SQL (MS SQL Server 2000/2005)

+0

Saajid Ismail, avez-vous vu mon commentaire ci-dessous que la réponse que vous avez choisi va forcer une analyse? De plus, il sera plus gourmand en CPU car il doit évaluer une expression sur CHAQUE RANGE dans le tableau entier ... – ErikE

Répondre

5

Essayez

select * 
from Periods 
where dateadd(qq,PeriodQuarter-1,dateadd(yy,PeriodYear -1900,0)) 
between @startDate and @endDate 
+0

Cela semble prometteur .. occupé à le tester. Merci! –

+0

Fonctionne comme un charme. Merci mec. Je ne savais pas que la fonction de dateadd pourrait aussi bien avec des trimestres. –

+0

Cela forcera une analyse, donc si vous avez un index sur le trimestre et l'année, le moteur ne sera pas en mesure de l'utiliser et les performances en souffriront. – ErikE

0

Je serais tenté d'ajouter 2 autres colonnes à la table ...

StartDate et EndDate - ceux-ci stockent la date à laquelle chaque joueur commence et se termine la période (à savoir dans votre exemple StartDate = 1er janvier 2009 et EndDate = 31 mars 2009)

Cela vous donnera plus de flexibilité si les trimestres sont définis différemment de ce que vous avez suggéré.

Si vous faites cela, la requête devient assez simple ...

select * 
from Periods 
where @startDate<Periods.StartDate and @endDate>Periods.EndDate 

Ceci est en supposant que vous voulez seulement inclure des périodes qui sont complètement encapsulées entre @StartDate et @EndDate. Si vous voulez des périodes qui se chevauchent, essayez quelque chose comme ...

select * 
from Periods 
where @EndDate>Periods.StartDate and @StartDate<Periods.EndDate 
+0

Bonne idée, bien que ce ne soit pas possible. Je devrais également changer les requêtes qui insèrent/mettent à jour à cette table, qui est unfeasable à ce stade de mon projet. En tout cas, il se résume toujours à résoudre le même problème. Nous devrons toujours comprendre comment convertir ces périodes en plages de dates –

2

A chercher au lieu d'un balayage est possible:

SELECT * 
FROM Periods 
WHERE 
    PeriodYear BETWEEN Year(@startdate) AND Year(@enddate) 
    AND PeriodYear * 4 + PeriodQuarter 
     BETWEEN Year(@startdate) * 4 + DATEPART(Quarter, @startdate) 
     AND Year(@startdate) * 4 + DATEPART(Quarter, @enddate) 

Explication:

Je compose un nouveau entier mis à l'échelle de deux pièces, l'année et le trimestre, en traitant chaque combinaison de l'année et quart comme un seul nombre.

Imaginez plutôt que je l'avais fait ainsi:

AND PeriodYear + (PeriodQuarter - 1)/4.0 
    BETWEEN Year(@startdate) + (DATEPART(Quarter, @startdate) - 1)/4.0 
    AND Year(@startdate) + (DATEPART(Quarter, @enddate) - 1)/4.0 

appeler mon expression originale « MULT » et ce nouveau « Div », voici quelques années et quarts et ce que ces expressions évalueront à:

Year Qtr Div  Mult 
2009 1 2009.00 8037 
2009 2 2009.25 8038 
2009 3 2009.50 8039 
2009 4 2009.75 8040 
2010 1 2010.00 8041 
2010 2 2010.25 8042 
2010 3 2010.50 8043

Alors maintenant, si nous courons une clause WHERE contre ces lignes:

WHERE Div BETWEEN 2009.25 AND 2010.00 

Vous peut voir comment il va retourner les lignes correctes. La version Mult fait exactement la même chose, en augmentant simplement l'année au lieu du trimestre en baisse. La raison pour laquelle je l'ai utilisé est parce que les mathématiques et la multiplication en nombres entiers sont plus rapides que les mathématiques et divisions fractionnaires.

La raison pour laquelle j'utilise deux conditions commençant juste avec l'année est de rendre la requête sargable. Nous voulons faire la recherche sur la base de l'année, ce qui n'est pas possible si nous le multiplions par 4 ou si nous faisons d'autres calculs. Nous obtenons donc l'analyse en seulement les bonnes années d'abord, puis affinez-la pour éliminer tous les quarts qui ne devraient pas être dans le résultat.

Une autre option consiste à ajouter une colonne calculée et à y placer un index. Cela ne nécessiterait aucune modification de l'insertion ou de la mise à jour de code (à condition d'utiliser correctement les listes de colonnes), mais vous permettrait de faire des calculs réguliers selon vos désirs.

+0

Je ne comprends pas vraiment la 2ème partie de la clause WHERE, avec la multiplication par 4. –