Why Sum in database query giving NULL - sql

Suppose I have a table named "Expense" and it has some month-wise expense which may contain some "NULL", now I want to check the yearly expenses in total with this below query:-
Select Sum(January) + Sum (February) ..... (I skipped the rest 10 months)
from Expense
This gives result as "NULL"
How can I avoid this situation? I think there are more convenient way to check the yearly sum

All arithmetic or logical operations involving NULL yield NULL. For example:
SELECT 1 + NULL -- NULL
You must convert NULL to zeros before you can + them:
SELECT
COALESCE(SUM(January), 0) +
COALESCE(SUM(February) , 0) +
...
It is also possible to add the columns first and then calculate the sum:
SELECT SUM(
COALESCE(January, 0) +
COALESCE(February, 0) +
)
Be advised that (i) SUM skips NULL values (ii) returns NULL instead of 0 if all values are NULL:
SELECT SUM(a) FROM (VALUES
(1),
(2),
(NULL)
) AS v(a) -- returns 3 instead of NULL
It will return NULL if all values encountered were NULL:
SELECT SUM(a) FROM (VALUES
(CAST(NULL AS INT)),
(NULL),
(NULL)
) AS v(a) -- returns NULL instead of 0

use coalesce function to convert null to 0 then use sum
Select Sum(coalesce(January,0)) + Sum (coalesce(February,0)) ..... (I skipped the rest 10 months)
from Expense

Just use coalesce [ with 0 as the second argument ] to replace nulls for all month columns, otherwise you can not get true results from aggregation of numeric values :
select sum(coalesce(January,0)+coalesce(February,0) ... )
from Expense

That because you have NULL values, you can use Case, Coalesce or IIF:
Select SUM(IIF(Col IS NULL, 0, Col))
Select SUM(CASE WHEN Col IS NULL THEN 0 ELSE Col END)
Select COALESCE(Sum(Col), 0)

Any arithmetic function will return null if there is at least one null value in the given column. That's why you should use functions like coalesce or isNull (MSSQL), NVL (Oracle).

You can use ISNULL(SUM(January),0).

Because null + value is always null and in your sample some months sums are null, you can avoid this by adding ISNULL
Select isnull(Sum(January),0) +
isnull(Sum(February),0)
--..... (I skipped the rest 10 months)
from Expense
Alternatively you can use below way:
Select Sum(
isnull(January,0) +
isnull(February,0)
)
--..... (I skipped the rest 10 months)
from Expense

Related

I need Total return NULL only If all values are NULL

A query like these
SELECT A,B,C,D, (A+B+C+D) as TOTAL
FROM TABLES
If A,B,C and D is NULL. i need to return NULL.
But if any one of the them is not NULL. Other will change from NULL to zero.
And total(a+b+c+d).
Now try this way
SELECT A,B,.. CASE WHEN (A IS NULL) AND (B IS NULL) AND ... THEN NULL
ELSE ISNULL(A,0) + ISNULL(B,NULL) +... END
But it is so long and I have a lot of total in this whole query.
What the best way I can use for this problem?
The semantics you want are the same as those provided by SUM.
SELECT A,B,C,D,
(SELECT SUM(val)
FROM (VALUES(A),
(B),
(C),
(D)) T (val)) AS Total
FROM YourTable
I would use COALESCE function.
Evaluates the arguments in order and returns the current value of the first expression that initially does not evaluate to NULL.
SELECT
CASE WHEN COALESCE(A,B,C,D) IS NOT NULL THEN
COALESCE(A,0 ) + COALESCE(B,0 )+ COALESCE(C,0 ) + COALESCE(D,0 )
END
FROM TABLES
COALESCE() is a function that you can use:
SELECT A,B,..
CASE WHEN COALESCE(A,B,C,D) IS NULL THEN NULL ELSE ISNULL(A,0) + ISNULL(B,0) +... END

SQL Server column divide with column with null value

I wanted my outcome to be something like below, the initial null value in either hit1 or hit0n1 become 0, and when hit1 divide by 0 then the percentage will become 0%.
Select CONVERT(varchar(10),ISNULL(a6.hit1*100,0)/NULLIF(a7.hit0n1, 0))+ '%'
.........
left join
(select category,hit,COUNT(hit) as hit1 from(Select Category,UpdateTime,due,
Case When UpdateTime < Due Then 1 Else 0 End As hit From FeedbackDetail Where StatusName ='Closed' and FeedbackDatetime>=DATEADD(day,-31, GETDATE())) a where hit = 1
Group by category, hit) a6 On a1.Category = a6.Category
left join
(select category,COUNT(hit) as hit0n1 from ( Select Category,UpdateTime,due,
Case when UpdateTime < Due then 1 else 0 end as hit From FeedbackDetail Where StatusName ='Closed' and FeedbackDatetime>=DATEADD(day,-31, GETDATE()) ) a
Group by category)
a7 on a1.Category = a7.Category
Expected Outcome
hit1 hit0n1 percentage
_____ _______ ____________
5 0 0%
0 0 0%
3 10 33.3%
but my code display this instead :
hit1 hit0n1 percentage
_____ _______ ____________
5 null NULL
6 6 100%
3 10 33.3%
there is null value in hit0n1, i want to elimate the null value and at the same time i want to avoid 0 number.
select hit1 = a6.hit1,
hit0n1 = isnull(a7.hit0n1, a6.hit1),
percentage = CONVERT(varchar(10),
ISNULL(a6.hit1 * 100.0,0) / ISNULL(a7.hit0n1, a6.hit1) ) + '%'
if you wanted the result in 3 decimal places,
use convert() to convert the calculation result to decimal(10,3) before convert to varchar(10)
percentage = CONVERT(varchar(10),
CONVERT(decimal(10,3),
ISNULL(a6.hit1 * 100.0,0) / ISNULL(a7.hit0n1, a6.hit1) )
) + '%'
EDIT : change to handle hit0n1 = 0
select
hit1,
hit0n1 = isnull(hit0n1, hit1),
percentage = CONVERT(varchar(10),
CONVERT(decimal(10,3),
ISNULL(ISNULL(hit1 * 100.0, 0) / NULLIF(ISNULL(hit0n1, hit1), 0), 0) )
) + '%'
EDIT : explanation on the percentage calculation
ISNULL(hit0n1, hit1) returns first non null value. If hit0n1 is null then it will return hit1 value
if hit0n1 is 0, that division will be error cause it is divide by 0. To handle it NULLIF( <expression> , 0) is use to return NULL value if <expression> is 0. And the result of the division will be NULL value
the final ISNULL() is to change the NULL value to 0
When you want to filter something, you can use WHERE or HAVING. As HAVING requires aggregation, I think it will be clearer to use WHERE. As, we do not want to have NULL values in the result, we can use:
WHERE a6.hit1 IS NOT NULL AND NULLIF(a7.hit0n1, 0) IS NOT NULL
We check for 0 only the a7.hit0n1 as 0 divided on something is valid statement.
Also, if you are working with huge amount of data, you can add filtering indexes on your tables, excluding the NULL values.
In place of NULL what do you want to replace then?
If you want to use the same value as first column then may be you can go with ISNULL(hit0n1,hit1)
NULLIF returns NULL if both expressions are equal otherwise it returns expression one which is also a NULL in your case.
Try the following query-:
Select hit1,
case when isnull(hit0n1,hit1)!=0 then isnull(hit0n1,hit1) end as [hit0n1],
cast(round((hit1/(case when isnull(hit0n1,hit1)!=0 then isnull(hit0n1,hit1) end)*100),2) as varchar(100))+'%'
from [YOUR_TABLE_NAME]
SQL Server 2014

SQL adding numbers while handling nulls

I have this statement here:
SELECT sum(table1.foo + table1.bar) AS Sum
FROM table1
GROUP BY Fname;
When I try to add the numbers from foo and bar if one value from foo or bar is null it throws the numbers and gives me a different count sum
foo | bar
6 4
5 null
9 1
2 1
3 null
I want it to add all the numbers giving me a total of 31
but in this case it gives me a total of 23
Would love some help! Thanks!
Use coalesce():
SELECT sum(coalesce(table1.foo, 0) + coalesce(table1.bar, 0)) AS Sum
FROM table1
GROUP BY Fname;
If you want the total, total on one row, remove the group by:
SELECT sum(coalesce(table1.foo, 0) + coalesce(table1.bar, 0)) AS Sum
FROM table1;
Any Number + NULL = NULL. You want to indicate to the engine that when it sees a NULL, it should treat that NULL value as 0.
SELECT sum(ISNULL(table1.foo, 0) + ISNULL(table1.bar,0)) AS Sum
FROM table1
GROUP BY Fname;
I believe you'll need to have SQL replace nulls with a zero using "ISNULL".
Try:
SELECT sum(ISNULL(fix_bat_sum.foo, 0) + ISNULL(fix_bat_sum.bar, 0) ) AS Sum

Select NULL if a calculated column value is negative in SQL

I have the following piece of sql below. The second line (commented out) contains my addition of a check to see if the calculation returns a negative value in which case it should select NULL. This case is within a block of multiple other case statements. Since my approach means running the same calculation twice is there a better alternative or more efficient method to selecting NULL if the value of this calculated column is negative, rather than doing two similar calculations?
Thanks
CASE
WHEN M.ALPHA = 'B' OR T.CT IN (0.001, 0.002) THEN NULL
-- WHEN ((M.VAL / NULLIF (M.VAL2, 0)) / (NULLIF (T.VAL, 0) / T.VAL2)) < 0 THEN NULL
ELSE (M.VAL / NULLIF (M.VAL2, 0)) / (NULLIF (T.VAL, 0) / T.VAL2)
END As WORLD
You could move the calculation to a subquery. For example:
select case
when CalculatedColumn > 42 then 'Hot'
when CalculatedColumn < 42 then 'Cold'
else 'Answer'
end as Description
from (
select 2 * col1 + 3 as CalculatedColumn
from YourTable
) SubQuery
Sometimes it's clearer to define the subquery in a with clause:
; with SubQuery as
(
select 2 * col1 + 3 as CalculatedColumn
from YourTable
) SubQuery
select case
when CalculatedColumn > 42 then 'Hot'
when CalculatedColumn < 42 then 'Cold'
else 'Answer'
end as Description
from SubQuery

ISNULL() not treating 0 value as NULL

I have script for revenue that multiplies invoice quantity to manual price and if manual price is null it will multiply to list price then if both null the value will be 0.
But my problem is I have 0 values on Manual Price so since it's the priority field I get a 0 Revenue which should not be because List price is not 0.
As much as possible I want CASE Statement as my last resort but if there is really no easier way then I'll use it.
SELECT INVOICE_QUANTITY * ISNULL(MANUAL_PRICE,ISNULL(LIST_PRICE,0)) as Revenue
You can add NULLIF to treat 0 values like NULL values:
SELECT INVOICE_QUANTITY * COALESCE(NULLIF(MANUAL_PRICE, 0), LIST_PRICE, 0) as Revenue
I've also changed the double ISNULL functions to a single COALESCE function.
Then don't use ISNULL(). Use the appropriate logic:
SELECT (INVOICE_QUANTITY *
(CASE WHEN MANUAL_PRICE <> 0 THEN MANUAL_PRICE
WHEN LIST_PRICE IS NOT NULL THEN LIST_PRICE
ELSE 0
END)
) as Revenue