Why Using COALESCE or CASE keep returning null - sql

I have the following SQL Query :
(SELECT ROUND(SUM(NBTOSUM)/1000000,1) FROM MyTable t2 WHERE t2.ELEMNAME IN ('A','B','C'))
Which works fine.
But Where there is no 'A','B','C' the result of the select is (null)
So to handle it, I did the following :
(SELECT COALESCE(ROUND(SUM(NBTOSUM)/1000000,1),0) FROM MyTable t2 WHERE t2.ELEMNAME IN ('A','B','C'))
And also try :
(SELECT
CASE
WHEN SUM(NBTOSUM)/1000000 IS NULL THEN 0
ELSE ROUND(SUM(NBTOSUM)/1000000,1)
END
FROM MyTable t2 WHERE t2.ELEMNAME IN ('A','B','C'))
But both keep returning null
What am I doing wrong ?

Move the WHERE restrictions to the CASE expression as well:
SELECT ROUND(SUM(CASE WHEN t2.ELEMNAME IN ('A','B','C')
THEN NBTOSUM ELSE 0 END) / 1000000, 1)
FROM MyTable t2;
Note that this trick solves the null problem and also avoids the need for an ugly COALESCE() call.

Your code should work as the SUM aggregation function will generate a single row of output regardless of whether the number of input rows is zero or non-zero. If there are no input rows or the values are all NULL then the output of the SUM will be NULL and then COALESCE would work.
Since you claim it does not then that suggests that there is something else going on in your query that you have not shared in the question.
You have braces around your statement suggesting that you are using it as part of a larger statement. If so, you can try moving the COALESCE to the outer query:
SELECT COALESCE(
(
SELECT ROUND(SUM(NBTOSUM)/1000000,1)
FROM MyTable
WHERE ELEMNAME IN ('A','B','C')
),
0
)
FROM your_outer_query;
That might fix the problem if you are somehow correlating to an outer query but your question makes no mention of that.
fiddle

Related

Anyway to use IN operator in the SELECT statement? If not, why?

This may come off as a feature request more than anything, but it would be nice if SQL allowed use of the IN operator in a select statement such as the one below. I want to create new_variable intable1based on the ID variable in table2, hence the case statement.
select ID,
case when ID in (select ID
from table2)
then 1
else 0
end as new_variable
from table1
I understand that SQL will give me an error if I run this, but why is that the case? It doesn't seem obvious to me why SQL developers couldn't enable the IN operator to be used outside of the WHERE clause.
Side note: I'm currently using a left join to avoid this issue, so I am not hung up on this.
select ID,
case when ifnull(b.ID, 0) = 0 then 0
else 1
end as variable_name
from table1
left join(select ID from table2) as b
on a.ID = b.ID
SQL definitely supports this:
select ID,
(case when ID in (select ID from table2)
then 1 else 0
end) as new_variable
from table1
Note that there is a comma after id.
This is standard SQL. If your database doesn't support it, it is a feature request (and one that all or almost all databases support).

How to nest a CTE (Common Table Expression)

I have the below query
With max_cm1 as (select * from tableA)
Select * ,
CASE WHEN TO_CHAR(CCP2.END_DATE,'MM/DD/YYYY') <> '09/09/9000' THEN 'CLOSED'
WHEN MAX_CM1.MAX_ROLE_CM IS NOT NULL AND HIST.PCMUID IS NOT NULL THEN 'ASSIGNED'
ELSE 'UNASSIGNED'
END STATUS
from max_cm1
Now I need to filter on the case statement. How can I do this?
You can use an alias eg: m.
With max_cm1 as (select * from tableA)
Select m.* ,
CASE WHEN TO_CHAR(CCP2.END_DATE,'MM/DD/YYYY') <> '09/09/9000' THEN 'CLOSED'
WHEN MAX_CM1.MAX_ROLE_CM IS NOT NULL AND HIST.PCMUID IS NOT NULL THEN 'ASSIGNED'
ELSE 'UNASSIGNED'
END STATUS
from max_cm1 m;
In your case, you don't need a CTE unless you are joining it with other table with some expressions in CTE. Directly you can fetch from table A with the same method if you are only interested in select '*'.
Your question is unclear. Also, the query as given is somewhat confusing, as it qualifies some columns with table names (CCP2 and HIST) that don't appear elsewhere in the query. Further, as written there seems to be no purpose to the CTE at all.
I'm assuming that what you want is to include the given CASE expression in the result set, but also use it within the WHERE clause to filter the results (e.g. WHERE CASE ... END = 'CLOSED'. The simple way to do this is to repeat the CASE expression; but of course duplicating logic is never a good choice. So the better way, which I think is the point of your question, is to include that derived column in a CTE so you can then refer to it by name in the WHERE clause.
It also looks like you are probably running into the issue of trying to select all columns (*) plus a derived column. The way around this is to qualify the * with the table name, or an alias as indicated in one of the other answers.
Putting this all together, I believe you want something like the following. I'm keeping the column expressions (e.g. HIST.PCMUID) as you wrote them although as written they make no sense. I'm guessing that tableA really represents some join of multiple tables.
WITH max_cm1 AS (
SELECT tableA.* ,
CASE WHEN TO_CHAR(CCP2.END_DATE,'MM/DD/YYYY') <> '09/09/9000' THEN 'CLOSED'
WHEN MAX_CM1.MAX_ROLE_CM IS NOT NULL AND HIST.PCMUID IS NOT NULL THEN
'ASSIGNED'
ELSE 'UNASSIGNED'
END STATUS
FROM tableA
)
SELECT *
FROM max_cm1
WHERE status = 'CLOSED'

Using self join/inner join to get the data by adding all the above rows data, in SQL Server

I am working with SQL server, the query details are as below:
Need to get the calculative column whose result will be the addition of all the above rows. And I can't use correlated queries, Lag and Lead as it is not supported.
I tried using self-join/inner join/left outer join, the only problem I am facing is due to group by clause of other columns the result is not coming as expected.
For example, data is like
Expected Output
But the output I am getting due to group by clause applied on Column4.
Output getting is like below
Is there some alternative of GROUP BY clause or other alternatives?
In SQL Server 2012+, you would simply use cumulative sum:
select d.*, sum(column3) over (order by column2)
from data d;
using subquery for earlier version of 2012
SELECT Column1,Column2,Column3,
( SELECT SUM(y.Column3)
FROM Data y
WHERE y.Column1 = x.Column1
AND y.Column2 <= x.Column2
) AS [Column5(Summation of Column3)]
FROM Data x
ORDER BY 1 ,2 ,3;
Query result
It is resolved!!
Earlier my query was like,
SELECT a.*,
CASE WHEN col4!= A THEN SUM col3 ELSE 0 END
FROM a
GROUP BY col4, *...
This groupby was causing issue as it was giving the expected output
The things I changes in the query is,
SELECT a.*,
SUM(CASE WHEN col4!= A THEN col3 ELSE 0 END)
FROM a
GROUP BY (CASE WHEN col4!= A THEN col3 ELSE 0 END)
Now it is giving result as expected.
Thank you everyone for the help!!

two query results in datetime compare in sql

I have two sql queries.
SELECT
DATE_FIRST_TABLE
FROM
FIRST_TABLE
and
SELECT
DATE_SECOND_TABLE
FROM
SECOND_TABLE
The above two queries may return single or multiple records.
I need to check the second query results if any date value is greater than any of the date value of first query results then it will evaluate true.
I need some suggestion on this.
Thanks.
Is this what you want?
select 'true'
from second_table
where date_second_table > (select max(date_first_table) from first_table)
The statement: "I need to check the second query results if any date value is greater than any of the date value of first query results then it will evaluate true." This is a bit hard to follow the logic. The above returns 'true' when the values of the second query are greater than all the values of the first query.
The answer may be:
select max('true')
from second_table
where date_second_table > (select min(date_first_table) from first_table)
A key addition is the max() function, which turns this into an aggregation function so it returns one row.
EDIT:
Your question is ambiguous about what to do in the "false" case. One answer, as you suggest in the comments is:
select (case when count(*) > 0 then 1 else 0 end)
from second_table
where date_second_table > (select min(date_first_table) from first_table);
A similar approach is to use an explicit join. Although this would perform less well, it may better capture the logic:
select (case when count(*) > 0 then 1 else 0 end)
from first_table t1 join
second_table t2
on t1.date_first_table > t2.date_second_table;
SELECT DATE_SECOND_TABLE FROM SECOND_TABLE WHERE DATE_SECOND_TABLE > (SELECT DATE_FIRST_TABLE FROM FIRST_TABLE)
When you say "it will evaluate to true", you do mean it will return the result presumably

Eliminate division by zero using an SQL Server CASE statement

I am trying to eliminate this division by zero error using CASE in my T-SQL SELECT statement. For some reason, I keep getting the error. Here is my logic.
SELECT
CASE
WHEN tb1.wpf = 0.000 THEN '0.000'
ELSE SUM(tb2.weight/tb1.wpf)
END AS Average
FROM Table1 tb1, table2 tb2
GROUP BY tb1.wpf
I did not include joins and all my logic to keep my question specific to this case. How can I get rid of this error?
The CASE is going to be applied to the aggregate, not individual bits. Try this:
SELECT SUM(Average) FROM (
SELECT
CASE
WHEN tb1.wpf = 0 THEN 0
ELSE tb2.weight / tb1.wpf
END AS Average
FROM Table1 tb1, table2 tb2
) a