如何在sql中返回零而不是使用case时选择没有行

时间:2018-03-24 14:48:27

标签: sql oracle oracle11g

如果我查询不存在的输出,那么我将不会返回任何内容。我正在寻找在该场景中返回的默认值(0)

select sum(case when a2.status='SUCCESS' THEN A2.a else 0 end) as success,
sum(case when a2.status='FAILED' THEN A2.a else 0 end) as failed,
sum(case when a2.status='ERROR' THEN A2.a else 0 end) as error
from
(select a.stauts,count(1) a 
from table1 a,table2 b
where a.id=b.id
a.date=sysdate
group by a.status)a2; 

注意:sysdate没有记录。我要求默认值“0”应该返回状态。

6 个答案:

答案 0 :(得分:2)

此查询应始终返回一行,即使没有匹配项:

select sum(case when a.status = 'SUCCESS' then 1 else 0 end) as success,
       sum(case when a.status = 'FAILED' then 1 else 0 end) as failed,
       sum(case when a.status = 'ERROR' then 1 else 0 end) as error
from table1 a join
        table2 b
        on a.id = b.id
where a.date = trunc(sysdate);

请注意,我更改了where逻辑。 sysdate(尽管它的名字)有一个时间组件。如果date有时间组件,您可能需要:

where a.date >= trunc(sysdate) and a.date < trunc(sysdate + 1)

编辑:

如果过滤条件没有匹配任何行,那么您将使用:

获得0
select count(case when a.status = 'SUCCESS' then 1 end) as success,
       count(case when a.status = 'FAILED' then 1 end) as failed,
       count(case when a.status = 'ERROR' then 1 end) as error
from table1 a join
        table2 b
        on a.id = b.id
where a.date = trunc(sysdate);

答案 1 :(得分:0)

您可以生成缺失值:

WITH cte AS (
     select a.status,count(1) a 
     from table1 a                  --JOIN syntax
     join table2 b
       on a.id=b.id
     WHERE a.date=sysdate           -- are you sure you want precision with time?
     group by a.status
), placeholder AS (
     SELECT *
     FROM cte
     UNION ALL
     SELECT *
     FROM (SELECT 'SUCCESS' AS status, 0 AS a FROM dual UNION ALL
           SELECT 'ERROR',   0 FROM dual UNION ALL
           SELECT 'FAILED',  0 FROM dual)  p
     WHERE NOT EXISTS (SELECT * FROM cte WHERE cte.status = p.status)
)
SELECT 
  sum(case when status='SUCCESS' THEN a else 0 end) as success,
  sum(case when status='FAILED' THEN a else 0 end) as failed,
  sum(case when status='ERROR' THEN a else 0 end) as error
FROM placeholder;

答案 2 :(得分:0)

我想到的唯一建议是在子查询中使用左连接并将整个WHERE逻辑移动到ON子句:

SELECT
    SUM(CASE WHEN a2.status = 'SUCCESS' THEN A2.a ELSE 0 END) AS success,
    SUM(CASE WHEN a2.status = 'FAILED'  THEN A2.a ELSE 0 END) AS failed,
    SUM(CASE WHEN a2.status = 'ERROR'   THEN A2.a ELSE 0 END) AS error
FROM
(
    SELECT a.status, COUNT(1) a 
    FROM table1 a
    LEFT JOIN table2 b
        ON a.id = b.id AND
           a.date = SYSDATE
    GROUP BY a.status
) a2;

您当前的查询使用的是古老的连接语法,这使得很难看到实际发生的情况。特别是,在您希望保留的加入期间,您很难看到是否可能丢弃信息。

答案 3 :(得分:0)

如果您使用COUNT(),则与NVL()的情况不同,您不需要COALESCE()NULL来处理SUM()。当参数为COUNT()或没有匹配行时,NULL将始终返回 value = 0 的行。GROUP BY也不需要。{ / p>

SELECT COUNT(CASE WHEN a.status = 'SUCCESS' THEN 1 END) AS success,
       COUNT(CASE WHEN a.status = 'FAILED'  THEN 1 END) AS failed,
       COUNT(CASE WHEN a.status = 'ERROR'   THEN 1 END) AS error
FROM table1 a
JOIN table2 b ON a.id = b.id
WHERE a.date = TRUNC(SYSDATE);

如果您只是想清楚,请测试这些查询并注意结果。

select SUM(1)    FROM DUAL WHERE 1=0; --NULL
select SUM(NULL) FROM DUAL WHERE 1=0; --NULL
select SUM(NULL) FROM DUAL WHERE 1=1; --NULL
select COUNT(1)  FROM DUAL WHERE 1=0;  -- 0
select COUNT(NULL) FROM DUAL WHERE 1=0; -- 0 
select COUNT(NULL) FROM DUAL WHERE 1=1; -- 0

Demo

答案 4 :(得分:0)

Aggregation without GROUP BY always returns a row, so your existing query will return NULLs.

To change a NULL to zero simply apply COALESCE:

select
   coalesce(sum(case when a2.status='SUCCESS' THEN A2.a end), 0) as success,
   coalesce(sum(case when a2.status='FAILED'  THEN A2.a end), 0) as failed,
   coalesce(sum(case when a2.status='ERROR'   THEN A2.a end), 0) as error
from
 (
   select a.status,count(1) a 
   from table1 a join table2 b
     on a.id=b.id
   where a.date=sysdate
   group by a.status
 ) a2;

答案 5 :(得分:0)

如果我想确保即使对于找不到任何要返回的行的查询也总会有结果,我会在双表上进行左连接(对于oracle):

select q.*  FROM DUAL d LEFT JOIN ( your_query )q on 1=1

通过这种方式,无论如何,你总会得到一排!