SQL Server column divide with column with null value - sql

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

Related

Case when then conditions without else

i am trying to do something like below where i dont want consider numbers which are greater then 30 in the below condition but the case condition taking else condition by default and adding them as null in value_a.
CASE WHEN a<10 and a!=0
THEN
a
WHEN a>10 and a<30
THEN
b
END AS value_a
out is as below
value_a
a
b
null
where as i want it to consider values only upto 30 and ignore other numbers
and output be like
value_a
a
b
Since you want to exclude the results where a >= 30 then use where clause to filter those results. And if you need a to be equal to 10 then you are missing the equal sign (adjusted below)
SELECT *,
CASE WHEN a<=10 and a!=0 THEN a
WHEN a>10 and a<30 THEN b
END AS value_a
code 2
select *,
case when transaction_type = 'c' and date < [enter date] THEN A
when transaction_type = 'c' and date > [enter date] THEN B
else end as final_value
FROM [table name]
WHERE transaction_type != 'd'
You will need to add '=' if you want to include 10 in your first condition.
You will also need to add '=' ifd you want to include 30 in your second condition.
At the end you will have to say you do not want to process if it is bigger than 30.
select CASE WHEN id<=10 and id>=0 THEN
'a'
WHEN id > 10 and id<=30 THEN
'b'
END value_a
from A
where id <= 30
Here is a small demonstration for SQLServer: DEMO
I believe it will help even if it is not in HIVEQL

Why Sum in database query giving NULL

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

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

SQL Server, Remove null values in a select case query

The code below generates around 300 rows, but only a small fraction of them has any value in column "Unit=3". The rest have null values, and hence many duplicate values in column "ekod" exists.
Does anyone know how to remove all rows with a null value in the column "unit=3"?
Best regards!
Result:
ekod unit=3
0004 NULL
0114 15
0114 NULL
0114 NULL
0120 NULL
0120 NULL
0120 46
0120 NULL
Code:
select
A.ekod
,case when A.unit='3' then count(*) end AS [Unit=3]
from [Stat_unitdata].[dbo].[XXX_YYY] A
group by a.ekod, a.unit
order by ekod
You can use sum.
select
A.ekod
,sum(case when a.unit='3' then 1 else 0 end) AS [Unit=3]
from [Stat_unitdata].[dbo].[XXX_YYY] A
group by a.ekod
order by ekod
As a note, if you don't care about ekods with zero units:
select a.ekod, count(*) as [Unit=3]
from [Stat_unitdata].[dbo].[XXX_YYY] a
where a.unit = '3'
group by a.ekod
order by a.ekod;
This returns only ekod values that have at least one unit = '3'.