【问题标题】:Display 0 when COUNT() returns nothing当 COUNT() 什么都不返回时显示 0
【发布时间】:2014-04-24 21:23:15
【问题描述】:

我正在尝试查找卡在某种状态的设备,并将它们按类型分组。我在数据库中查询处于该状态的设备的count(),然后进行几次检查以查看这些设备是否符合条件。但是,它没有显示没有任何count() 的类型。我需要显示所有类型,即使 count() 没有任何内容。

例如,目前我有这个:

TYPE   COUNT(DEVICE.NAME)
TYPE1                 200
TYPE2                 100
TYPE3                  50

我需要它像这样回来:

TYPE   COUNT(DEVICE.NAME)
TYPE1                 200
TYPE2                 100
TYPE3                  50
TYPE4                   0
TYPE5                   0

这是我目前所拥有的:

SELECT device.type, count(device.name)
FROM device
LEFT OUTER JOIN (SELECT type, name
                  FROM device) b
  ON device.name = b.name
WHERE device.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60))
  AND device.status != 6 AND device.status != 8 AND device.status != 13
GROUP BY device.type
ORDER BY count(device.name) DESC;

后来意识到表 b 上的联接是不必要的,但我将把它留在问题中,以便答案仍然准确反映问题。

我在子查询上尝试了所有类型的连接,结果都是一样的。

【问题讨论】:

  • 我意识到 h471 上的联接是不必要的,我已将其从 SQL 语句中删除。很抱歉有任何混淆。

标签: sql oracle join count subquery


【解决方案1】:

如果您使用left outer join,则需要将它用于查询中的所有连接(通常)。否则,您可能会“撤消”之前的加入。

但是,我认为这不是您唯一的问题。表达式 count(d.name) 必须至少返回 1(除非 name 可以是 NULL)。

SELECT d.type, count(h471.id)
FROM device d INNER JOIN
     (SELECT type, name
      FROM device
     ) b
     ON d.name = b.name
WHERE d.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60)) and
      d.status != 6 AND d.status != 8 AND d.status != 13
GROUP BY d.type;

使用外连接时,您还必须注意where 子句。但是,在这种情况下,您只引用了device 表。如果切换到left outer join 不能解决问题,那么问题出在where 子句中——它正在过滤掉额外的设备。如果是这种情况,则将 where 子句移至条件聚合:

SELECT d.type,
       sum(case when d.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60)) and
                       d.status != 6 AND d.status != 8 AND d.status != 13
                  then 1 else 0
            end)
FROM device d LEFT OUTER JOIN
     (SELECT type, name
      FROM device
     ) b
     ON d.name = b.name 
GROUP BY d.type;

出于性能原因,您也许可以将某些条件移回where 子句。

另外,我没有加入表 b。它只会增加行数(如果device 中的多行具有相同的名称)或什么都不做。

【讨论】:

  • 请看我对h471加入主帖的评论。
  • @AustinMoore 。 . .我进行了修改,因此答案与更改后的问题一致。
  • @GordonLinoff 假设 name 是设备表中的唯一值(可能是这种情况但不确定),那么您可以在第二次删除整个 b 子查询使用带有CASE 语句的SUM 的示例。还忘记在第一个查询中将h471.id 从 COUNT 中取出。
  • @BateTech。 . .我完全同意,但代码是故意存在的,它似乎是有目的的。一个神秘的目的。
  • @AustinMoore 。 . .我会采用更保守的方法,而不是改变问题。您可以编辑问题并指出 joinb 是不必要的,但如果您完全删除它,那么所有答案看起来都会更具误导性。
【解决方案2】:

我认为你需要类似的东西

SELECT type, SUM(COUNT_RESULT)
  FROM (

          SELECT device.type, 0 COUNT_RESULT
          FROM device

          UNION ALL

          SELECT device.type, count(1)
          FROM device, h471
          WHERE device.recnum = h471.id
            AND device.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60))
            AND device.status != 6 AND device.status != 8 AND device.status != 13

)        
GROUP BY type

【讨论】:

  • 谢谢!你的回答也解决了我的问题。它类似于@GordonLinoff 的回答。不过,因为Gordon解释了问题和解决方法,所以我会选择他的作为正确答案。
【解决方案3】:

看起来你想要的可以通过将整个查询变成一个子查询并应用 COALESCE 来获得 0 缺失的结果。

SELECT d0.type, COALESCE(d.cnt,0) FROM device d0
LEFT OUTER JOIN (
  SELECT device.type, count(device.name) AS cnt
  FROM device
  LEFT OUTER JOIN (SELECT type, name
                    FROM device) b
    ON device.name = b.name
  WHERE device.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60))
  AND device.status != 6 AND device.status != 8 AND device.status != 13
  GROUP BY device.type) d
ORDER BY COALESCE(d.cnt,0) DESC;

【讨论】:

  • COALESCE() 在按照您的建议实施时似乎不起作用。我仍然缺少计数为 0 的类型。
  • COALESCE 在这种情况下将无济于事,除非COUNT 在子查询b 中。在原始查询中使用COUNT,它永远不会返回NULL,因此COALESCE 不会有任何影响。 COUNT 列上的所有 NULL 值仍将返回 0。
  • 你说得对,我忽略了这一点。我很确定我现在解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 2016-03-11
  • 1970-01-01
  • 2020-12-22
  • 2019-08-05
  • 2018-07-18
  • 1970-01-01
相关资源
最近更新 更多