Reputation: 67
If I query a output that doesn't exist then I will get nothing returned. i'm looking for default (0) is returned in that scenario
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;
Note: There is no records for sysdate. I required default value "0" should be return for status.
Upvotes: 1
Views: 1687
Reputation: 176
If I wanted to ensure there is always a result even for a query that wouldn't find any row to return, I would do a left join on dual table (for oracle):
select q.* FROM DUAL d LEFT JOIN ( your_query )q on 1=1
This way you will always get back a row, no matter what!
Upvotes: 0
Reputation: 1271003
This query should always return one row, even if nothing matches:
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);
Note that I changed the where
logic. sysdate
(despite its name) has a time component. If date
has a time component, you may want:
where a.date >= trunc(sysdate) and a.date < trunc(sysdate + 1)
EDIT:
If the filter condition matches no rows, then you will get 0
using:
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);
Upvotes: 2
Reputation: 60502
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;
Upvotes: 0
Reputation: 31716
If you use COUNT()
, you don't need NVL()
or COALESCE()
to handle NULL
s ,unlike the case for SUM()
. COUNT()
will always return a row with value=0 when the argument is NULL
or when no rows are matched.GROUP BY
too wouldn't be required.
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);
If you just want to be clear, test these queries and pay attention to the result.
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
Upvotes: 0
Reputation: 522722
The only suggestion which comes to mind would be to use a left join in your subquery and move the entire WHERE
logic to the ON
clause:
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;
Your current query is using archaic join syntax which makes it hard to see what is actually happening. In particular, it makes it hard to see whether or not you might be discarding information during the join which you wish to retain.
Upvotes: 0
Reputation: 176174
You could generate missing values:
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;
Upvotes: 0