【问题标题】:SELECT COUNT(*) - return 0 along with grouped fields if there are no matching rowsSELECT COUNT(*) - 如果没有匹配的行,则返回 0 以及分组字段
【发布时间】:2012-11-27 23:54:48
【问题描述】:

我有以下疑问:

SELECT employee,department,count(*) AS sum FROM items 
WHERE ((employee = 1 AND department = 2) OR 
      (employee = 3 AND department = 4) OR 
      (employee = 5 AND department = 6) OR 
      ([more conditions with the same structure]))
      AND available = true
GROUP BY employee, department;

如果一对“employee-department”没有项目,则查询不返回任何内容。我希望它返回零:

 employee | department | sum 
 ---------+------------+--------
 1        |          2 |      0
 3        |          4 |     12  
 5        |          6 |   1234   

编辑1

看起来这是不可能的,正如 Matthew PK 解释的 in his answer to a similar question。我错误地假设 Postgres 可以以某种方式从 WHERE 子句中提取缺失值。

EDIT2

有一些技巧是可能的。 :) 感谢 Erwin Brandstetter!

【问题讨论】:

  • 您只想要 WHERE 子句中的员工和部门组吗?
  • @FarukSahin,实际上没有,可能还有其他条款,但我只想按“员工”和“部门”分组。相应地更新了问题
  • @FarukSahin,误读了您的评论。在输出中,我只想要分组字段和总和。
  • 所以,您想限制某些(员工、部门)组的输出,而不希望所有(员工、部门)组?
  • 我没有看到标签是postgresql。检查此链接,其中完全相同的问题得到解答:stackoverflow.com/questions/4866162/…

标签: sql postgresql count left-join aggregate-functions


【解决方案1】:

不可能?接受挑战。 :)

WITH x(employee, department) AS (
   VALUES
    (1::int, 2::int)
   ,(3, 4)
   ,(5, 6)
    -- ... more combinations
   )
SELECT x.employee, x.department, count(i.employee) AS ct
FROM   x
LEFT   JOIN items i ON i.employee = x.employee
                   AND i.department = x.department
                   AND i.available
GROUP  BY x.employee, x.department;

这会给你正是你所要求的。如果employee 和department 不是整数,则强制转换为匹配类型。

来自@ypercube 的每条评论:count() 需要位于items 的非空列上,因此我们得到0 用于不存在的条件,而不是1。

此外,将其他条件添加到 LEFT JOIN 条件(在本例中为 i.available),这样您就不会排除不存在的条件。

性能

在评论中解决其他问题。
这应该表现得非常好。对于更长的标准列表,(LEFT) JOIN 可能是最快的方法。

如果您需要尽快,请务必创建一个multicolumn index,例如:

CREATE INDEX items_some_name_idx ON items (employee, department);

如果 (employee, department) 应该是 PRIMARY KEY 或者您应该在两列上有一个 UNIQUE 约束,那也可以解决问题。

【讨论】:

  • 这真是太棒了:) 后续问题——这个查询的性能如何? (桌子会很大)。我可以选择在应用程序级别实现所要求的功能
  • @tokarev:我在回答中添加了一些内容。
  • 是的,但只有在 it breaks 时将新对添加到表中,因为它在 CTE 中不存在。
  • @Clodoaldo:这是一个有意的效果。问题中的查询具有它搜索的条件列表。问题是不寻找所有现有组合的完整列表。 这将SELECT DISTINCT employee, department FROM items作为CTE x更容易实现。
【解决方案2】:

基于 Erwin 的加入建议,这个really works:

with x(employee, department) as (
   values (1, 2)
   )
select
    coalesce(i.employee, x.employee) as employee,
    coalesce(i.department, x.department) as department,
    count(available or null) as ct
from
    x
    full join
    items i on
        i.employee = x.employee
        and
        i.department = x.department
group by 1, 2
order by employee, department

【讨论】:

    【解决方案3】:
    select employee, department,
        count(
            (employee = 1 and department = 2) or 
            (employee = 3 and department = 4) or 
            (employee = 5 and department = 6) or
            null
        ) as sum
    from items
    where available = true
    group by employee, department;
    

    【讨论】:

    • 不错bool or null,从来没想过这个优雅的解决方案。但是使用NULLIF((condition) ,'false') 可能更容易阅读。或SUM( CASE WHEN ... THEN 1 ELSE 0 END).
    • 如果表中不存在给定的“employee-department”对,这将不起作用。查看我对问题的编辑
    • @Igor 一旦你习惯了它(它会很快)你会欣赏它带来的清洁。
    猜你喜欢
    • 2021-09-05
    • 1970-01-01
    • 2016-10-19
    • 2020-01-07
    • 2021-08-25
    • 1970-01-01
    • 2013-04-27
    • 2021-10-18
    • 1970-01-01
    相关资源
    最近更新 更多