SQL循环

时间:2009-02-17 17:02:35

标签: sql sql-server loops

我正在为Billboard公司的系统构建此报告。 他们有一个存储所有广告牌的表,除其他数据外,广告牌还有一个开始日期和结束日期(两者都可以为空)。
如果出于某种原因,广告牌必须停止使用,它们会设置完成日期,并且在该日期之后使用它将变得无法使用。与开始日期相同(如果他们只是设置了一个新的电路板,它可以在设定的开始日期后使用)。

在本报告中,我必须得到所有可能的广告位的总和。

所以,让我说在我选择的时期(4周,例如)     *在第1周,有500个可用的板     *在第2周,一块板变得不可用(可以使用498块板)     *在第3周,两个电路板可用(可制作501个电路板)
    *在第4周,一个电路板变得可用,另一个电路板变得不可用(可制作501个电路板)

那么在这期间我应该总共拥有1990年可用的董事会,这就是我所追求的结果。

如何在单个查询中获取此信息? 这几周将来自一个HTML表单,我必须在查询之前将它们转换为日期,所以我只想知道可以使用多少板的日期。
获取特定日期的电路板数量的查询如下:

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')  

我不能只为每个日期添加ANDOR条件,因为我需要为不同的日期重新计算。我想过使用WHILE但是无法弄清楚如何在这种情况下做到这一点。这就是我被困的地方...... 如果有人需要,我会发布更多细节。

谢谢,Gabe

7 个答案:

答案 0 :(得分:3)

不知道这是否是您正在寻找的,但可能是朝着正确方向迈出的一步。

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  

答案 1 :(得分:1)

这不是您问题的答案,但您应该考虑使用BETWEEN代替AND

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

IMO这更具可读性。

答案 2 :(得分:0)

如果您可以将表单中的日期转换为(可能是临时的)表格,那么您的查询可以是:

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)

答案 3 :(得分: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)

答案 4 :(得分:0)

SQL中没有WHILE。要循环,您可以加入另一个表。

您没有指定它,但我认为广告牌会在星期一的某一天更改可用性,比如周日,并且它们不能每周更改多次。

你需要做的是创建一个包含所有可能周数的表格,当这种变化发生时,我们称之为DT日期,一个日期列x,每周有一个日期(周日?)。

然后做这样的事情:

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

答案 5 :(得分:0)

假设您使用的是SQL Server 2005或更高版本,则可以使用CTE执行此操作,如以下示例所示。在我的示例中,您需要设置一个日期以及您希望从此日期回顾的周数:

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

答案 6 :(得分:0)

这将为您提供2009年前4周的总数。要检查另一年,请将下面查询中的两次出现更改为您感兴趣的年份。

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 

如果您需要超过前4周,请继续在内部查询中添加数字,其中包含UNION。