2009-02-17 8 views
0

Je construis ce rapport dans un système pour une société Billboard. Ils ont une table qui stocke tous leurs panneaux d'affichage, et entre autres données, les panneaux d'affichage ont une date de début et une date de fin (les deux peuvent être nulles).
Si, pour quelque raison que ce soit, un panneau d'affichage doit cesser d'être utilisé, il fixe une date de fin et il deviendra impossible de l'utiliser après cette date. Idem avec Date de début (dans le cas où ils ont juste mis en place une nouvelle carte et il sera disponible pour une utilisation après une date de début définie).SQL Looping

Dans ce rapport, je dois obtenir la somme de tous les spots publicitaires possibles sur une période donnée.

Alors, laisse dire que, pour la période que j'ai choisi (4 semaines, par exemple)
* En semaine 1 il y a 500 planches avaiable
* En semaine 2 un conseil d'administration est devenu indisponible (faisant 498 planches avaiable)
* En semaine 3 deux planches se sont avaiable (faisant 501 planches avaiable)
* En semaine 4 un conseil d'administration est devenu avaiable et un autre est devenu indisponible (faisant 501 planches avaiable)

alors je devrais avoir un total de 1990 conseils avaiable dans cette période, c'est le résultat que je suis après.

Comment puis-je obtenir ceci dans une seule requête?
Les semaines viendront d'un formulaire HTML et je dois les convertir en dates avant la requête, donc je vais juste avoir les dates où je veux savoir combien de cartes sont disponibles.
La requête pour obtenir le montant des conseils pour un jour spécifique est comme ceci:

SELECT 
    COUNT(IdBillboard) 
FROM 
    tBillboards 
WHERE 
    (StartDate IS NULL OR StartDate <= '2009-01-05 00:00:00') 
    AND (FinishDate IS NULL OR FinishDate >= '2009-01-05 00:00:00') 

Je ne peux pas ajouter AND et OR conditionals pour chaque jour parce que je dois un peu un nouveau dépouillement judiciaire pour les dates distinctes. J'ai pensé à l'aide d'un WHILE mais je ne pouvais pas comprendre exactement comment le faire pour cette affaire. Voilà où je suis coincé ... Je posterai plus de détails si quelqu'un en a besoin.

Merci, Gabe

+0

Je pense que vous vouliez dire 498 planches dans la semaine 2. – achinda99

+0

Haha. Je l'ai réparé. Merci – Gabe

+0

Est-ce que tout est toujours délimité par semaine? –

Répondre

3

Je ne sais pas si c'est ce que vous cherchez, mais pourrait être un pas dans la bonne direction.

SELECT 
    SUM(CASE WHEN 
    (StartDate IS NULL OR StartDate <= '2009-01-05 00:00:00') 
     AND (FinishDate IS NULL OR FinishDate >= '2009-01-05 00:00:00') 
    THEN 1 
    ELSE 0 END)) Week1Count, 
    SUM(CASE WHEN 
    (StartDate IS NULL OR StartDate <= '2009-01-12 00:00:00') 
     AND (FinishDate IS NULL OR FinishDate >= '2009-01-12 00:00:00') 
    THEN 1 
    ELSE 0 END)) Week2Count 
FROM 
    tBillboards 
+0

Merci, Barry! Je n'avais même pas pensé à mettre les résultats dans des colonnes différentes. Mais ce n'est toujours pas parfait. Les fonctions de regroupement doivent être SUM au lieu de COUNT, et après cela, la clause where n'est même pas pertinente. Si vous l'éditez afin que je puisse vérifier comme accepté, je serai plus que content de le faire – Gabe

+0

Ouais je me suis précipité la réponse. Édité maintenant. – Barry

0

Si vous pouvez obtenir les dates de la forme dans un (éventuellement temporaire) table, alors votre requête peut être:

SELECT 
    COUNT(t.IdBillboard) 
FROM 
    tBillboards r, tDates d 
WHERE 
    (t.StartDate IS NULL OR StartDate <= d.date) 
    AND (t.FinishDate IS NULL OR FinishDate >= d.date) 
0
SELECT COUNT(*) 
FROM 
    (
    SELECT DATEADD(ww, num, @initdate) AS wd 
    FROM (
     SELECT 0 AS num 
     UNION ALL 
     SELECT 1 
     UNION ALL 
     SELECT 2 
     UNION ALL 
     SELECT 3 
     ) w 
    ) weeks, Billboards bb 
WHERE wd BETWEEN NULLIF(bb.StartDate, wd) AND NULLIF(bb.EndDate, wd) 
1

Ce n'est pas une réponse à votre question, mais vous devriez pensez à utiliser BETWEEN au lieu de AND s.

WHERE 
    (StartDate IS NULL) OR 
    StartDate BETWEEN '2009-01-05' AND '2009-01-05' 

IMO c'est beaucoup plus lisible.

0

Il n'y a pas de WHILE dans SQL. Pour boucler, vous vous joignez à une autre table.

Vous ne le spécifiez pas mais je suppose que les panneaux d'affichage changent de disponibilité un jour de la semaine, disons dimanche, et qu'ils ne peuvent pas changer plusieurs fois par semaine.

Ce que vous devez faire est de créer un tableau de toutes les semaines possibles où ce changement peut se produire, appelons-le DT pour date, avec une seule colonne de date x qui a une date par semaine (dimanche?).

faire quelque chose comme ceci:

select count(*) from tBillboards b 
inner join DT d 
    on (b.startdate is null or b.startdate <= d.x) 
     and (b.finishdate is null or b.finishdate < d.x) 
where d.x between period_start and period_end 
0

En supposant que vous utilisez SQL Server 2005 ou version ultérieure, vous pouvez le faire en utilisant un CTE comme dans l'exemple suivant. Dans mon exemple, vous devez définir une date et le nombre de semaines que vous souhaitez regarder en arrière à partir de cette date:

DECLARE @dtNow DATETIME 
DECLARE @iNumberOfWeeks INT 
SET @dtNow = '2009-01-21' 
SET @iNumberOfWeeks = 2; 


WITH CountForPeriod (IdBillBoard, StartDate, FinishDate, NumberOfWeeksBack) AS 
(
    SELECT IdBillBoard, StartDate, FinishDate, 1 AS NumberOfWeeksBack 
    FROM tBillBoards 
    WHERE (StartDate <= @dtNow) 
    AND (FinishDate >= @dtNow) 

    UNION ALL 

    SELECT b.IdBillBoard, b.StartDate, b.FinishDate, 1 + NumberOfWeeksBack 
    FROM tBillBoards b 
    JOIN CountForPeriod c 
    ON (b.StartDate <= DATEADD(dd, -7 * c.NumberOfWeeksBack, @dtNow)) 
    AND (b.FinishDate >= DATEADD(dd, -7 * c.NumberOfWeeksBack, @dtNow)) 
) 
SELECT NumberOfWeeksBack, COUNT(*) 
FROM CountForPeriod 
WHERE NumberOfWeeksBack <= @iNumberOfWeeks 
GROUP BY NumberOfWeeksBack 
0

Cela vous donnera le total pour les 4 premières semaines en 2009. Pour vérifier une autre année , changer les deux occurrences de 2009 dans la requête ci-dessous pour l'année qui vous intéresse.

select sum(Count) as Total 
from (
    SELECT w.Week, Count(*) as Count 
    FROM tBillboards b 
    inner join (
     select 1 as Week 
     union all 
     select 2 
     union all 
     select 3 
     union all 
     select 4 
    ) w on StartDate is null or datepart(ww, StartDate) <= w.Week 
     and FinishDate is null or datepart(ww, FinishDate) >= w.Week 
    where isnull(year(StartDate), 2009) <= 2009 
     and isnull(year(FinishDate), 2009) >= 2009 
    group by w.Week 
) a 

Si vous avez besoin de plus que les 4 premières semaines, continuer à ajouter des numéros à la requête interne avec les partenaires sociaux en elle.