prevent divide by zero when both values are obtained from a calculation - sql

I'm trying to complete the following:
(value_a + value_b)/(value_c + value_d)
Usually I have avoided a divide by zero error with something like this:
CASE WHEN value_a + value_b = 0
THEN 0
ELSE (value_a + value_b)/(value_c + value_d)
END
For some reason in this isn't working, which makes me wonder if in the past one of my result sets have never included zero's.
Any pointers on this would be gratefully received.

You're checking the numerator, not the denominator:
CASE WHEN value_c + value_d = 0
THEN 0
ELSE (value_a + value_b)/(value_c + value_d)
END
Anothere way is to use NULLIF and COALESCE:
COALESCE((value_a + value_b)/NULLIF((value_c + value_d),0)
,0)

Related

embedding null if within other null if statements

The query below is part of a larger query, but once I add it in, i get a division by 0 error.
(SUM(likes + comments + video_views) / nullif(SUM(influencer_starting_followers),
0))/ (SUM(average_likes + average_comments + average_views) /nullif(SUM(followers_count),
0)) AS Achieved,
I'm quite new to sql and i'm not entirely sure how to go about changing this section (primarily the denominator as shown below) so that Achieved is only calculated if the query below is not= 0 or null
(SUM(average_likes + average_comments + average_views) /nullif(SUM(followers_count)
Your second division is not "nullif protected"
(SUM(likes + comments + video_views) / nullif(SUM(influencer_starting_followers),
0))/ nullif(SUM(average_likes + average_comments + average_views),0) /nullif(SUM(followers_count),
0)) AS Achieved,
nullif returns Null if the 2 parameters are equal, that's to avoid to divide by zero.

CAST(somenumber as VARCHAR(10)) + somestring returns Error converting data type varchar to numeric

I'm trying to combine a min and max salary with a hyphen for display in a report. I feel like I've done this a hundred times but I still can't figure out why I'm getting the "Error converting data type varchar to numeric" especially since I'm trying to convert a numeric to varchar not the other way around.
amt_exp_formatted = CASE
WHEN a.class_code IN ('9997','9998','9999') THEN 0
--ELSE CAST(e.min_sal as VARCHAR(10)) + '-' + CAST(e.max_sal as VARCHAR(10))
ELSE CONVERT(VARCHAR(1), 1) + CONVERT(VARCHAR(1), 'a')
END
In the above example if I use 'a' I get the error. If I change 'a' to '9' then it works AND it appends 9 to the 1 (i.e. 19) rather than adding them together which is exactly what I want but with a character string. I've tried both CAST and CONVERT with no luck. I know I shouldn't need the second CONVERT on the letter 'a' but I was just trying to force the data types to be the same just in case. I have no doubt at all I'm missing something simple but I can't seem to get it so I figured it wouldn't hurt to ask the community.
Thank you!
A case expression returns one value with a determinate type. If any returned fork returns a number, then number it is. And strings get converted.
So, be sure you are returning a string in all cases:
(CASE WHEN a.class_code IN ('9997', '9998', '9999')
THEN '0'
ELSE CONCAT(e.min_sal, '-', e.max_sal)
END)
CONCAT() automatically converts the arguments to strings.
This is becuase you are mixing the data type. in the first part of case you were returning 0 while in the else part you're converting it to varchar(). - you can try the below returning 0 as also varchar
amt_exp_formatted = CASE
WHEN a.class_code IN ('9997','9998','9999') THEN '0'
--ELSE CAST(e.min_sal as VARCHAR(10)) + '-' + CAST(e.max_sal as VARCHAR(10))
ELSE CONVERT(VARCHAR(1), 1) + CONVERT(VARCHAR(1), 'a')
END

How to change number of digits after decimal point?

I have this line in my query:
CASE WHEN count(n.Counter) <> 0 THEN (cast(count(n.Counter) as float)/count(t.Counter)) * 100 ELSE 0 END as percent
I'm getting results like 79.565974946.
I want to get a result like 80% (with no digits after the decimal point and with '%' sign).
How can i do that?
You need to ROUND and then, because you're trying to do formatting, convert to a string before adding the %:
CONVERT(varchar(20),
ROUND(
CASE WHEN count(n.Counter) <> 0
THEN (cast(count(n.Counter) as float)/count(t.Counter)) * 100
ELSE 0 END
,0)) + '%' as percent
Also, there may be a typo here - it looks like you're trying to avoid a divide by zero error, but you're testing the wrong operand (n.Counter rather than t.Counter) so you may still get a division by zero from this code.
If using MySQL, just use the ROUND function.
CASE WHEN count(n.Counter) <> 0 THEN ROUND(cast(count(n.Counter) as float)/count(t.Counter)) * 100 ELSE 0 END as percent
Try this:
CASE WHEN count(n.Counter) <> 0 THEN round((cast(count(n.Counter) as float)/count(t.Counter)) * 100,0) ELSE 0 END as percent
Where are you showing the data? Adding % should be done at the front end application. Just use this and format it in fornt end if you use
round(
case when count(n.counter) <> 0
then (cast(count(n.counter) as float)/count(t.counter)) * 100
else 0 end
,0))

How to round this result in SQL SELECT statement

I need a method to round the result returned from the following statement:
CASE
WHEN 0 <> (sod.XDFFLT - sod.DUEQTY)
THEN (sod.XDFFLT - sod.DUEQTY)
ELSE ''
END AS Balance
Which resides in this SELECT statement.
SELECT TOP (10000) som.ORDNUM
,som.NAME
,som.ADDR1
,som.ADDR2
,som.CITY
,som.STATE
,som.ZIPCD
,som.CNTRY
,som.CUSTPO
,COALESCE(cpd.CUSTPRT, sod.PRTNUM) AS CustomerSku
,cpd.CUSTPRT
,som.CUSTID
,sod.PRTNUM
,ps.PMDES1
,sod.CURQTY
,sod.DUEQTY
,sod.XDFFLT
,sod.SHPQTY
,CASE
WHEN 0 <> (sod.XDFFLT - sod.DUEQTY)
THEN (sod.XDFFLT - sod.DUEQTY)
ELSE ''
END AS Balance
,sod.LINNUM + sod.DELNUM AS LineDelNum
,CASE
WHEN 12 <= len(sod.UDFREF)
THEN substring(sod.UDFREF, 9, 4)
ELSE sod.UDFREF
END AS Skid
Replace the CASE with this:
,CASE
WHEN 0 <> (sod.XDFFLT - sod.DUEQTY)
THEN ROUND((sod.XDFFLT - sod.DUEQTY), <number_of_decimals>)
ELSE NULL
END AS Balance
Make sure to replace the <number_of_decimlas> with the appropriate number of decimals you want the number to be rounded to.
greater than 0 will return a number which is rounded on the right side of the comma (decimal point)
less than 0 will return a number which is rounded on the left side of the comma (decimal point)
Also, don't use a blank string in the ELSE clause of your case since this will cause a datatype missmatch and generate an error (a CASE must return a single datatype). Hence, it is better to replace this with NULL, since your first condition will always return a number.

SQL String Manipulation and character replacement

I have a database with a list of old ItemID's that need updating to a new format.
The old format is of the form 8046Y and the new format moves the 4th digit to the end and prepends a hyphen and adds a 0 if it's a single digit. The old format also uses alpha characters when the number goes over 9 for example 464HB where the H represents 17. I also need to add a 1 to the beginning of the new format. All this can be done with string manipulation in SQL I hope.
Some examples:
8046Y becomes 1804Y-06
464HB becomes 1464B-17 (H = 17)
Can anyone give me some pointers as to how to go about this in SQL?
I got as far as:
select '1' + LEFT(ItemID, 3) + RIGHT(ItemID,1) + '-' + '0' + SUBSTRING(ItemID,3,1) from items
But the conversion from a=10 to z=36 stumped me
Try this:
select
'1'
+ left(#str,3)
+ right(#str,1)
+ '-'
+ case
when substring(#str,4,1) like '%[0-9]%' 1 then right('00' + substring(#str,4,1),2)
else cast(10 + ascii(substring(#str,4,1))-ascii('A') as varchar(2))
end
Explanation: If the 4th character is a digit, then do not change the value and append it after padding with a zero. Otherwise, use ASCII to get the ASCII value for that character, get it's difference with the value for 'A' and add the offset of 10.
Demo
Since I don't know if there are any other special character to consider except 'H' only included this single character.
DECLARE #val CHAR(5) = '464HB'
SELECT #val, '1' + LEFT(#val,3)+SUBSTRING(#val,5,1)+'-'+CASE WHEN +SUBSTRING(#val,4,1)='H' THEN '17' ELSE '0'+SUBSTRING(#val,4,1) END
select '1' + LEFT(ItemID, 3) + RIGHT(ItemID,1) + '-'
+CASE RIGHT(LEFT(ItemID,1),2)
WHEN 'a' then 10
WHEN 'b' THEN 11
etc...
END [NewItemID]
from items
Just add the appropriate cases in that format.
I do it only for the challenge, i dont recommend to use
DECLARE #id varchar(5) = '8046Y'
--SET #id = '464HB'
SELECT
'1' +
LEFT(#id, 3) +
RIGHT(#id, 1) +
'-' +
CASE WHEN ISNUMERIC(RIGHT(LEFT(#id, 4), 1)) = 1 THEN
RIGHT(LEFT(#id, 4), 1)
ELSE
RIGHT('00' + CONVERT(VARCHAR, ASCII(RIGHT(LEFT(#id, 4), 1)) - 64 + 9), 2)
END
-64 for the Start of ASCII A and +9 for your convention
Personally, I'd create a function for it.
Create a variable to handle the new value.
Manipulate the positions through SUBSTRING, you can also use RIGHT or LEFT
When adding zeros in single digit numbers, just do conditional statement
Regarding the conversion of letters to numbers(e.g. letter H), the converted value of the first letter is 65 assuming it's all capital. So, A=65, B=66, H=72 and so on. Use this data in manipulating the values. Uhm, I'll give you my thoughts but you can optimize it (since I don't have lots of time).
Taking your example of H=17, so A=10. Just subtract 55 in the conversions. So H=72(-55) becomes 17. This is applicable to all letters (in uppercase only).
I think this much is more than enough to guide you. Hope this would help.