ISNULL() not treating 0 value as NULL - sql

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

Related

how to add case condition in sql to calculate sum if there is column(weight) of type varchar and data is numeric or null or NA

select stick,sum(convert(float,weight)) as total
from lod_description group by stick
above query works fine but when null or NA comes in the weight field as data it gives error as varchar to int not allowed
Expected Result:
stick | total
oldstick 10.01
newstick 20.034
Ideally your weight column should be numeric, and not text. You could sum a CASE expression which returns 0 in the event that weight be a non numeric string.
SELECT stick,
SUM(CASE WHEN weight REGEXP '^[0-9]+(\.[0-9]+)?$'
THEN CAST(weight AS DECIMAL(10, 6)) ELSE 0.0 END) AS total
FROM lod_description
GROUP BY stick;
Assuming OP's current query works for everything except when weight is NULL or ='NA', how about:
select stick,sum(convert(float,weight)) as total
from lod_description
where weight is not NULL
and weight != 'NA'
group by stick
If this is Sybase ASE, SQLAnywhere or IQ:
select stick,sum(convert(float,weight)) as total
from lod_description
where isnumeric(weight) = 1
group by stick
NOTE: I don't know if Sybase Advantage has a comparable function but shouldn't be too hard to review the associated reference manual to find out.
And if OP is set on using case:
select stick,
sum(case when isnumeric(weight)=1
then convert(float,weight)
else 0.00
end) as total
from lod_description
group by stick
-- or
select stick,
sum(case when weight is NULL or weight = 'NA'
then 0.00
else convert(float,weight)
end) as total
from lod_description
group by stick

Find percentage of rows that meet a condition without rounding

I'm trying to find the percentage of rows that meet a specific condition. My query is close but the answer is always rounded to the nearest whole number.
For instance this query below is returning 6 but it should return 6.25. Meaning 6.25% of the rows meet that condition. How would I do this?
select sum(case when name like 'H%' then 1 else 0 end) * 100 / count(*)
from category
Just add a decimal point:
select sum(case when name like 'H%' then 1.0 else 0 end) * 100 / count(*)
from category;
Postgres does integer division.
You can also express this using avg():
select avg(case when name like 'H%' then 100.0 else 0 end)
from category;
The decimal point is not needed. Although Postgres does integer division of integers, it calculates average of integers using decimal points.
And this can be phrase more simply (assuming that name is not NULL):
select avg( (name like 'H%')::int ) * 100
from category;
You need a decimal value, otherwise, since both the numerator and denominator are integers, Postgres does integer division.
But here, I would just use avg() - for which you don't need an integer value:
select avg(case when name like 'H%' then 1 else 0 end) * 100
from category
You're performing integer division, and thus omitting everything right of the decimal point. If you use a floating-point literal 100.0, you should be OK:
select sum(case when name like 'H%' then 1 else 0 end) * 100.0 / count(*)
from category

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 select a column if

Within SQL is it possible to select a column only if it meets my Criteria?
IF p.Amount != 0.0
{ select p.Amount from Price p }
This is part of a much larger SQL will be used to filter the column from being displayed if there are values over 0.0
SQL criteria are used to select rows, not columns. I have generally found it makes life easier to always select the same columns for a specific query, and later choose whether or not to display them using view logic.
You need to use the CASE statement. Transact-SQL - CASE
USE AdventureWorks2012;
GO
SELECT ProductNumber, Category =
CASE ProductLine
WHEN 'R' THEN 'Road'
WHEN 'M' THEN 'Mountain'
WHEN 'T' THEN 'Touring'
WHEN 'S' THEN 'Other sale items'
ELSE 'Not for sale'
END,
Name
FROM Production.Product
ORDER BY ProductNumber;
GO
Do you want it to not be visible at all? Or just display some other predefined value inside it?
Because if you want the column to not appear at all, but only in some cases, that can not be done.
However, you can return a different result in the column, should it suffice for you. Use CASE WHEN:
SELECT
CASE WHEN p.amount< 700 THEN p.amount
ELSE 0
END
FROM Price p;
If you only want to show values greater than 0.0, you can use a where clause:
select p.amount
from t
where p.amount > 0
If you want non-positive values to be shown, and blanks (NULLs) for the rest, then do:
select (case when p.amount > 0 then p.amount end)
from t
If you only want rows returns when all values are greater then zero, then here is one way:
select p.amount
from (select t.*,
sum(case when p.amount > 0 then 1 else 0 end) over () as Pgt0
count(*) over () as cnt
from t
) t
where Pgt0 = cnt
If you actually want to remove the column when, say, all the values are the same, then you need a more complicated expression. SQL SELECT queries define the columns and don't have dynamically configurable columns.
You can use IFF function in SQL Server:
SELECT IIF(p.Amount != 0.0 ) as amount
FROM price p

sql query: subtract from results the corresponding USD, YEN value which has Type='r'

I need help with a query. Consider the following table:
I need to select first the sum of each Code from table. I am doing it with simple sum and group by statement. Then I have to subtract the results from each code sum where type='r'
1) Say for first part of query, we will get 2 rows from SUM (one with total USD and one with total YEN)
2) Now I need to subtract from these results the corresponding USD, YEN value which has Type='r'
I have to do it inside SQL and not a stored procedure.
Why not use a WHERE statement to say WHERE Type != 'r' so that those values never even get added to sum in the first place...
SELECT `Code`, SUM(`Amount`) AS `Total`
FROM `Table`
WHERE `Type` != 'r'
GROUP
BY `Code`;
Something like that.
select code, l.amount - r.amount
from
(select code, sum(amount) as amount from my_table group by code) l
left join (select code, sum(amount) as amount from my_table where type = 'r' group by code) r
on l.code = r.code
You can do this in a single, simple query:
select
code,
sum(case when type = 'r' then (-1 * amount) else amount end) as sum
from
yourtable
group by
code
Basically, you're changing the sign of the rows that have type = 'r', so when you sum all rows for a particular code you'll get the correct answer.
Does it have to be a single query?
I'd say SUM the total, then SUM the subcategory where Type='r', then subtract one from the other.
You could do this in one line of SQL, but I'm pretty sure it would be either joining the table with itself or using a subquery. Either way, it's doing the same amount of work as the above.
Try:
select code,
sum(amount) gross_total,
sum(case when type = 'r' then amount else 0 end) type_r_total,
sum(case when type != 'r' then amount else 0 end) net_total
from yourtable
group by code;
to see the overall totals, type R only totals and non-type R totals for each currency on one row per currency, in a single pass.