我正在为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')
我不能只为每个日期添加AND
和OR
条件,因为我需要为不同的日期重新计算。我想过使用WHILE
但是无法弄清楚如何在这种情况下做到这一点。这就是我被困的地方......
如果有人需要,我会发布更多细节。
谢谢,Gabe
答案 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。