对于 table 中不存在的组合,如何在 COUNT 中包含 "zero"

How to include "zero" in COUNT for combinations which don't exist in the table

我有一个约会 table 存储日期、一天中的时间 (AM/PM)、建筑物和房间 -- 对于它们中的每一个:

create table appt (day char(10), tod char(2), bl char(2), rm char(3));
insert into appt values ('2016-01-28', 'AM', 'B1', '101');
insert into appt values ('2016-01-28', 'AM', 'B1', '303');
insert into appt values ('2016-01-28', 'PM', 'B2', '222');
insert into appt values ('2016-01-29', 'PM', 'B3', '456');

我需要输出每个日期 + 时间 + 建筑物的约会计数。

这很简单:

select day, appt.tod, appt.bl, count(*)
from appt
group by day, tod, bl

但我需要显示所有组合,甚至 计数为空的组合 -- 而且,我卡住了。

使用 JOIN 没有帮助,因为它只是将实际约会乘以一天中不同时间的数量或不同建筑物的数量。

我该如何解决这个问题?给我一个提示让我走上正确的道路就足够了。谢谢!

http://sqlfiddle.com/#!9/4c055/2 查看数据库和请求。

已编辑--

目标数据库:MS SQL Server 2012.

我确实有 table 所有建筑物。我没有 table 与 'AM' 和 'PM'.

预期结果:

day         tod   bl cnt
----------   --   --  --
2016-01-28   AM   B1   2
2016-01-28   AM   B2   0
2016-01-28   AM   B3   0
2016-01-28   PM   B1   0
2016-01-28   PM   B2   1
2016-01-28   PM   B3   0
2016-01-29   AM   B1   0
2016-01-29   AM   B2   0
2016-01-29   AM   B3   0
2016-01-29   PM   B1   0
2016-01-29   PM   B2   0
2016-01-29   PM   B3   1

已编辑 2016-06-09--

我目前想出了以下代码:

select refday.day, reftod.tod, refbl.bl, count(*)

-- Template.
from (select distinct day from appt) refday
cross join (select distinct tod from appt where tod in ('AM', 'PM')) reftod
cross join (select distinct bl from appt) refbl

-- Real data.
left join appt
on appt.day = refday.day
  and appt.tod = reftod.tod
  and appt.bl = refbl.bl

group by refday.day, reftod.tod, refbl.bl
order by refday.day, reftod.tod, refbl.bl

但计数仍然不正常,days/tod 没有完成约会时返回 1:

day        tod  bl  cnt
----------  --  --  --
2016-01-28  AM  B1  2
2016-01-28  AM  B2  1
2016-01-28  AM  B3  1
2016-01-28  PM  B1  1
2016-01-28  PM  B2  1
2016-01-28  PM  B3  1
2016-01-29  AM  B1  1
2016-01-29  AM  B2  1
2016-01-29  AM  B3  1
2016-01-29  PM  B1  1
2016-01-29  PM  B2  1
2016-01-29  PM  B3  1

我错过了什么?

WHERE 子句添加到 select 正确的记录会将它们从计数中删除,但会让我回到方块 1:并未显示所有组合。

SQL 无法为不存在的输入提供结果。

相反 需要确保这些输入存在。

一个 标准模式是创建所需的输出行,将数据左连接到该 'template',然后根据模板的列进行聚合。

SELECT
   DatesAndTimes.date,
   DatesAndTimes.tod,
   Buildings.bl,
   COUNT(appt.id)
FROM
   DatesAndTimes
CROSS JOIN
   Buildings
LEFT JOIN
   appt
       ON  appt.date = DatesAndTime.date
       AND appt.tod  = DatesAndTime.tod
       AND appt.bl   = Buildings.bl
       AND appt.rm   = Buildings.rm
WHERE
       DatesAndTimes.date >= '2016-01-28'
   AND DatesAndTimes.date <  '2016-02-01'
   AND Buildings.something = 'interesting'
GROUP BY
   DatesAndTimes.date,
   DatesAndTimes.tod,
   Buildings.bl

像这样的案例使 'calendar table' 非常有用。你应该已经有了某种 'buildings table'。

但同样可以接受table 使用子查询、常见的 table 表达式或任何你想要的东西来创建初始的 'template' LEFT JOIN.