【问题标题】:SQL Count non existing itemSQL Count 不存在的项目
【发布时间】:2014-01-06 11:35:51
【问题描述】:

我有表格组,

ID  NUMBER
STATUS  VARCHAR2(20 BYTE)

我可以统计如下状态数。

select g.status, count(*) from groups g group by g.status;

STATUS                 COUNT(*)
-------------------- ----------
OK                            2 
NOK                           1 

我还有另一个状态,比如 PENDING、REJECTED。但是表中不存在任何项目,但我希望它们以零计数显示,如下所示。

STATUS                 COUNT(*)
-------------------- ----------
OK                            2 
NOK                           1 
PENDING                       0 
REJECTED                      0 

使之成为可能的 SQL 语句是什么?

【问题讨论】:

  • 不同的状态是否都在另一个表中?
  • 没有Status表,
  • 您无法显示不存在的信息。
  • 您指定的查询将默认执行。您是否尝试在表格中插入这些状态?如果它显示为 NULL,请尝试使用 ISNULL(COL,REPLACE_VALUE)

标签: sql postgresql select count left-join


【解决方案1】:

试试这个

SELECT A.status, COUNT(DISTINCT G.ID) statusCnt
FROM (SELECT 'OK' status FROM DUAL
      UNION 
      SELECT 'NOK' status FROM DUAL
      UNION 
      SELECT 'PENDING' status FROM DUAL
      UNION 
      SELECT 'REJECTED' status FROM DUAL
     ) AS A 
LEFT JOIN groups G ON A.status = G.STATUS 
GROUP BY A.status;

【讨论】:

  • 出现以下错误:从命令中的第 15 行开始出错:SELECT A.statusName, COUNT(DISTINCT G.ID) statusCnt FROM (SELECT 'OK' status UNION SELECT 'NOK' status UNION SELECT 'PENDING ' status UNION SELECT 'REJECTED' status ) AS A LEFT JOIN groups G ON A.status = G.STATUS GROUP BY A.status 命令行错误:17 列:7 错误报告:SQL 错误:ORA-00923:FROM 关键字不在预期的位置找到 00923. 00000 - “在预期的位置未找到 FROM 关键字” *原因:*操作:
  • @mmc18 您已将内部查询中的列别名从statusName 更改为status,但您没有在第一行更改列名添加SELECT A.status, 而不是SELECT A.statusName,
  • @mmc18 我在答案中更改了列别名。检查更新的答案
  • 有同样的错误,我认为这不是关于外星人:从第 16 行开始的错误命令:SELECT A.status, COUNT(DISTINCT G.ID) statusCnt FROM (SELECT 'OK' status UNION SELECT' NOK' 状态 UNION SELECT 'PENDING' 状态 UNION SELECT 'REJECTED' 状态)作为 LEFT JOIN 组 G ON A.status = G.STATUS GROUP BY A.status 命令行错误:18 列:7 错误报告:SQL 错误: ORA-00923:在预期的地方找不到 FROM 关键字 00923. 00000 - “在预期的地方找不到 FROM 关键字” *原因:*操作:
  • @mmc18 您使用的是哪个数据库服务器?
【解决方案2】:

如果存在包含状态列表的表,您可以这样编写查询:

我想你的州登记处已经调用了 STATES

SELECT
    states.status,
    (select count(*) from groups g where g.status = states.status)
FROM states

或者:

SELECT
    s.status, count(*)
FROM states s
LEFT OUTER JOIN groups g
    ON s.status = g.status
GROUP BY s.status

否则无法获取此信息

编辑(评论后)

请创建一个表:

CREATE TABLE states
(id int,
status varchar(20))

在您的表中,将状态字段替换为 fk 到状态表

【讨论】:

  • 我建议不要使用子选择,而是使用连接。如果你的表变大,子选择的性能会急剧下降。
  • @Seb:如果你使用 LEFT OUTER JOIN,你必须使用 GROUP BY(也有点重)
  • 如果您在 group.status 字段上有一个不应该有问题的索引。
  • @Seb:如果你已经索引了状态字段,子查询也是如此
  • @Seb:我添加了带有左外连接的版本来完成我的答案;)
【解决方案3】:

我认为对结果使用 LEFT OUTER JOIN 将是一个简单而快速的解决方案。

与其他答案一样,假设您有一个“状态”表列出了所需的“状态”,您可以将“状态”表与“分组依据”结果连接起来,并将 NULL 值填充为 0。

SELECT s.status,COALESCE(gs.numGroups,0)
FROM states AS s
LEFT OUTER JOIN
  (SELECT status,count(*) AS numGroups FROM groups AS g GROUP BY status) AS gs
  ON gs.status=states.status

结果看起来像这样(在 SQLite 中测试):

status            numGroups
---------------------------
OK                2
NOK               1
PENDING           0
REJECTED          0

请注意,COALESCE 函数在其他数据库中的调用方式可能不同,例如SQLite 中的 IFNULL 或 SQL server 中的 ISNULL

【讨论】:

    【解决方案4】:

    试试这个

    select g.status, ISNULL(COUNT(*),0) from groups g group by g.status;
    

    【讨论】:

    • GROUP By 一个不存在的值不会让它神奇地出现,即使是 ISNULL
    猜你喜欢
    • 2015-01-22
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-25
    • 1970-01-01
    相关资源
    最近更新 更多