如何在COUNT中为表中不存在的组合

时间:2016-06-08 10:27:20

标签: sql join count aggregate-functions

我有一个约会表,存储日期,时间(上午/下午),建筑物和房间 - 每个人:

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。

我有一张包含所有建筑物的桌子。我没有'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

但计数仍然不行,在没有预约的情况下返回1天/ tod:

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子句以选择正确的记录将从计数中删除它们,但会使我回到正方形1:并非显示所有组合。

1 个答案:

答案 0 :(得分:1)

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

需要确保存在这些输入。

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

In[4]: list1 = ["A", "B" , "C"]

list2 = ["E", "F", "G"]
In[5]: newlist = map(lambda x, y: x+","+y, list1, list2)
In[6]: newlist
Out[6]: ['A,E', 'B,F', 'C,G']

这样的案例使得“日历表”非常有用。而你应该已经有了某种“建筑物表”。

但是,使用子查询,公用表表达式或任何你想要的东西同样可以创建def joinWithComma(*args): return ",".join(args) In[15]: newlist = map(joinWithComma, list1, list2, list1, list2) In[16]: newlist Out[16]: ['A,E,A,E', 'B,F,B,F', 'C,G,C,G'] 的初始“模板”。