在两个单独的 SQL 表上计算总数

Counting totals on two separate SQL tables

我有两个(相同的)表

待办事项

ItemBatch | Item
   abc       Pickup sticks
   abc       Tie my shoe
   xyz       Suck my thumb
   abc       Climb a tree

完成列表

ItemBatch | Item
   abc      Tie my shoe

我试图从每个 [ItemBatch] 中的每一个中获取一个计数,但不确定在一个查询中是否真的可行?

单独做

select count(*) from ToDoList where ItemBatch = 'abc' /* repeat for each ItemBatch */

select count(*) from DoneList where ItemBatch = 'abc' /* repeat for each ItemBatch */

并在前端分配给变量,这样我就可以获得以下内容:

ItemBatch | Total | DoneList | DoneList - ToDoList
   abc       3        1           2
   xyz       1        0           1

有没有一个查询可以一下子给我完整的输出?我尝试加入初学者

select count(cc.[ItemBatch]), count(cq.[ItemBatch])
from ToDoList cc
left join DoneList cq on cc.[ItemBatch] = cq.[ItemBatch]

很快意识到这行不通...

然后我想

select
(select count(*) from ToDoList where [ItemBatch] = 'abc' ) as Total,
(select count(*) from DoneList where [ItemBatch] = 'abc' ) as DoneList

但我无法弄清楚如何一次性为每个 ItemBatch 输出所有行,group by 不适用于最后一个语句:

select
    (select [ItemBatch], count([ItemBatch]) from ToDoList group by [ItemBatch) as Total,
    (select [ItemBatch], count([ItemBatch]) from DoneList group by [ItemBatch]) as DoneList

如果您使用正确的 JOIN 条件,您的 LEFT JOIN 方法将起作用:

select count(cc.[ItemBatch]), count(cq.[ItemBatch])
from ToDoList cc left join
     DoneList cq
     on cc.[ItemBatch] = cq.[ItemBatch] AND cc.Item = cq.Item;

ItemBatch 你会添加一个 GROUP BY:

select ItemBatch, count(*), count(cq.ItemBatch)
from ToDoList cc left join
     DoneList cq
     on cc.ItemBatch = cq.ItemBatch AND cc.Item = cq.Item
group by cc.ItemBatch

由于 SELECT 语句中的计算,您应该尝试在您的案例中使用 OUTER APPLY

The OUTER APPLY operator returns all the rows from the left table expression irrespective of its match with the right table expression. For those rows for which there are no corresponding matches in the right table expression, it contains NULL values in columns of the right table expression.

所以,你的声明应该是:

SELECT 
        cc.ItemBatch, 
        COUNT(*) as Total,
        ISNULL(dl.DoneListTotal, 0) as DoneList,
        COUNT(*) - ISNULL(dl.DoneListTotal, 0) as [DoneList - ToDoList]
FROM ToDoList cc
     OUTER APPLY (SELECT COUNT(*) DoneListTotal
                  FROM DoneList cq
                  WHERE cc.ItemBatch = cq.ItemBatch) dl
GROUP BY cc.ItemBatch, dl.DoneListTotal;

使用 UNION ALL 获取 2 个 table 的所有 ItemBatch,另外还有 2 个列 ToDoDone 来指示哪个 table 他们属于并聚合:

SELECT ItemBatch,
       SUM(Todo) ToDo,
       SUM(Done) Done,
       SUM(Todo) - SUM(Done) Difference
FROM (
  SELECT ItemBatch, 1 ToDo, 0 Done FROM ToDoList
  UNION ALL
  SELECT ItemBatch, 0, 1 FROM DoneList 
) t
GROUP BY ItemBatch

参见demo
结果:

> ItemBatch | ToDo | Done | Difference
> :-------- | ---: | ---: | ---------:
> abc       |    3 |    1 |          2
> xyz       |    1 |    0 |          1