divisor is equal to zero in sql need to add some sort of try catch - sql

I have this query that i get errors when data gets loaded to this table and the divisor is zero which is the b. living_units column. I want to know if I can do some sort of try catch or if its zero to show null instead of failing or something that will help not error out?
SELECT a.SERVICE_TYPE_GRP,
a.HSIA_TYPE,
a.STAT_DYN_IND,
a.VIDEO_IND,
a.VOICE_IND,
a.CUST_CNT,
b.LIVING_UNIT_CNT,
a.DT_MODIFIED,
a.CUST_CNT / b.LIVING_UNIT_CNT AS ALLRGN_TK_RT_PCT
FROM ( SELECT lp.SERVICE_TYPE_GRP SERVICE_TYPE_GRP,
lp.HSIA_TYPE HSIA_TYPE,
lp.STAT_DYN_IND STAT_DYN_IND,
lp.VIDEO_IND VIDEO_IND,
lp.VOICE_IND VOICE_IND,
lp.DT_MODIFIED DT_MODIFIED,
SUM (lp.CUST_CNT) CUST_CNT
FROM RPT_SUBSCR_REGION_DTL lp
GROUP BY SERVICE_TYPE_GRP,
HSIA_TYPE,
STAT_DYN_IND,
VIDEO_IND,
VOICE_IND,
DT_MODIFIED) a,
( SELECT DT_MODIFIED, SUM (LIVING_UNIT_CNT) LIVING_UNIT_CNT
FROM RPT_REGION_CUST_DTL
WHERE dt_modified = (SELECT dt_modified
FROM ls_dt_modified
WHERE NAME = 'RPT_REGION_CUST_DTL')
GROUP BY DT_MODIFIED) b
WHERE a.DT_MODIFIED = b.DT_MODIFIED;
The error i get is ORA-01476: divisor is equal to zero.

If you have a complex divisor expression and a NULL result is acceptable, there is an alternative that does not require repeating the divisor expression:
a.CUST_CNT / nullif(b.LIVING_UNIT_CNT, 0)
The NULLIF function returns NULL if the first parameter is equal to the second parameter. In this case it returns NULL if b.LIVING_UNIT_CNT is equal to zero. And anything divided by NULL also becomes NULL. It's a bit of a "trick" maybe, but it saves the expression repetition of the CASE statement.

Try a case statement:
case
when b.LIVING_UNIT_CNT = 0 -- the divisor
then 0 -- a default value
else a.CUST_CNT / b.LIVING_UNIT_CNT
end
ALLRGN_TK_RT_PCT

Related

About COALESCE in PostgreSQL and handling Null Values

I was practicing SQL with PostgreSQL and I got stuck using COALESCE, maybe someone can tell me where I am going wrong.
I have a table with four columns: title, height_cm, length_cm, and width_cm. I want to multiply three last ones and get the column "size". The problem is that the whole dataset has many NULL values and 0s which I would like to skip and return the biggest value possible with the three columns (i.e. if only height has value, return that value, if the three columns have values multiply the three). If no column has a value return "NO VALUE FOUND".
I was not able to manage "skipping" the Null values (I haven't really started with the 0s yet since I am stuck in the beginning). I thought that this would have done the trick but it did not work.
SELECT title, height_cm, length_cm, width_cm,
COALESCE(
height_cm * length_cm * width_cm,
length_cm * width_cm,
height_cm * length_cm,
height_cm * width_cm,
height_cm,
length_cm,
width_cm, 'NO VALUE FOUND') AS size
FROM artworks
ORDER BY size ASC
LIMIT 10
First of all, the system does not recognize "NO VALUE FOUND" (but when I add a 0 instead, it recognizes it), secondly, when I take the text out, the system still considers the NULL values. I am able to make it work adding
WHERE height_cm IS NOT NULL AND length_cm IS NOT NULL AND width_cm IS NOT NULL
But I thought that the main idea of COALESCE was to be able to skip the NULL values. Any suggestions?
Regarding the 0s, if I add:
WHERE height_cm != 0 AND length_cm != 0 AND width_cm != 0
I lose the rows that have values but which also have one 0.
Thanks!
EDIT with the solution from the answers
In the end I used a CTE in combination with the answers from the people who helped below, this is the final query:
WITH query AS (SELECT title, height_cm, length_cm, width_cm,
(CASE WHEN height_cm IS NULL AND length_cm IS NULL AND width_cm IS NULL
THEN 0
ELSE (COALESCE(height_cm, 1) * COALESCE(length_cm, 1) * COALESCE(width_cm, 1))
END) AS size
FROM artworks)
SELECT *
FROM query
WHERE size > 0
ORDER BY size ASC
LIMIT 10
The datatypes of all elements passed to coalesce should be the same, but I would apply coalesce to each column separately and use the default value of 1 if it's null:
coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1) as size
which is logically the same as what you've coded.
You'll need a special check in case they are all null, for which you may (ab)use coalesce too:
case
when coalesce(height_cm, length_cm, width_cm) is null then null -- or 0
else coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1)
end as size
You'll have to pick either null or some special value (eg 0) when they are all null. You may render it as "NO VALUE FOUND" to the user as you wish.
"NO VALUE FOUND" is a string type on the other hand 0 is numeric that's why when you are using 0 it does not create problem because in case of 0 all the data for this column is numeric data type but when you are trying to use string it has been created issue of mixing two different data types which will not be allowed by sql engine
I agree with Bohemian on the use of a single expression. However, I think the final expression you want returns a string:
(case when height_cm is null and length_cm is null and width_cm is null
then 'NO VALUE FOUND'
else (coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1))::text
end) as size
Or, just live with a NULL value meaning that the value is not available.
It sounds like the function you actually want to use here is GREATEST:
SELECT
title,
height_cm,
length_cm,
width_cm,
COALESCE(
GREATEST(
height_cm * length_cm * width_cm,
length_cm * width_cm,
height_cm * length_cm,
height_cm * width_cm,
height_cm,
length_cm,
width_cm)::text, 'NO VALUE FOUND') AS size
FROM artworks
ORDER BY size
LIMIT 10;
The GREATEST function will automatically pick up on the largest non NULL value already. So, you only need COALESCE here as a catch-all for the case where the height, length, and width, all happen to be NULL at the same time.

how to use is null with case statements

Hi can any one say me how to write query in sql server management studio for statement =>if(isnull("GROSS_SF")=1 or "GROSS_SF"=0,0,"GROSS_SALES"/"GROSS_SF")
by using case statement :
CASE
WHEN ("GROSS_SF"=1 or "GROSS_SF"=0) isnull then 0
else "GROSS_SALES"/"GROSS_SF"
end/* i am getting error if i write it like this */
thanks in advance
If you want to avoid a divide by zero, while at the same time also handling NULL, then you may try the following logic:
CASE WHEN COALESCE(GROSS_SF, 0) = 0
THEN 0
ELSE GROSS_SALES / GROSS_SF END AS output
To be clear, the above logic would return a zero value should either the GROSS_SF be zero or NULL.
I think what are you looking for is IFNULL, look here https://www.w3schools.com/sql/sql_isnull.asp
You are close. You can do:
(CASE WHEN "GROSS_SF" IS NULL OR "GROSS_SF" = 0 THEN 0
ELSE "GROSS_SALES" / "GROSS_SF"
END)
In SQL, divide by zero errors are often avoided using NULLIF():
"GROSS_SALES" / NULLIF("GROSS_SF", 0)
However, that returns NULL rather than 0. If you really want zero:
COALESCE("GROSS_SALES" / NULLIF("GROSS_SF", 0), 0)
This is a bit shorter to write and almost equivalent to your version (this returns 0 if "GROSS_SALES" is NULL, which your version does not).
You can use NULLIF() to prevent arithmetic divide by zero errors :
select . . . ,
GROSS_SALES / nullif(GROSS_SF, 0)
from table t;
However, this would return null instead of error, if you want to display 0 instead then you need to use isnull() (MS SQL Specific) or coalesce() (SQL Standard).
So, you can express it :
select . . . ,
isnull(GROSS_SALES / nullif(GROSS_SF, 0), 0)
from table t;

"!="/NOT perhaps not working properly in SQLite

I have a table with about a hundred rows. It has a column is_gallery that contains either 1, 0, or NULL. If I do...
SELECT * WHERE is_gallery != 1
or
SELECT * WHERE NOT (is_gallery = 1)
it excludes the rows where is_gallery is null. I can manage to get a proper response if I do
SELECT * WHERE (is_gallery = 0 OR is_gallery is null)
But shouldn't the "!=" or NOT work? Isn't there a way to just return the rows where is_gallery doesn't equal 1 without testing for every other possibility?
You can use the IS and IS NOT operators instead of = and !=. These treat NULL like a normal value.
SELECT * FROM yourTable WHERE is_gallery IS NOT 1
The best thing to use is coalesce as in:
SELECT *
WHERE coalesce(is_gallery,0) != 1;
what coalesce does, is replaces any null value in that column with the second parameter. In the example above, any nulls in the "is_gallery" column will be replaced with 0 before it is compared with 1. So will of course return true.
On NULL realize that a NULL value isn't equal to ANYTHING - not even NULL itself. It cannot be compared - so when "comparing", it always will return FALSE. On NULL, it has a special operator which is "IS NULL" or "IS NOT NULL"

SQL -VB - Does it evaluate the else even when the if is true?

I am trying to prevent #error being displayed in a report I am creating
This happens when I divide 2 numbers and one of them is zero
So I tried using an if/switch statement to check if either of the 2 number are 0 before doing the divide :
=IIf(Fields!Field1.Value = 0
or Fields!Field2.Value = 0
or Not(IsNumeric(Fields!Field1.Value))
or Not(IsNumeric(Fields!Field2.Value)),
0,
(Fields!Field1.Value/Fields!Field2.Value)*100
)
=Switch(
Fields!Field1.Value = 0 or Fields!Fields.Value = 0, 0,
IsNumeric(Fields!Field1.Value) or IsNumeric(Fields!Fields.Value), (Fields!Field1.Value/Fields!Fields.Value)*100
)
Both of these still throw the error. It seems that the else condition is still evaluated even if the if statement is true
If I change the code to just print X or Y for the if and else, then it works - so there isn't an error in the if statement
This sems ridiculous to me
Please tell me I am doing something wrong? I can't believe the language would evaluate the else when the if is true
EDIT
So it seems that the else condition is evaluated. So how do you get around a potential divide by zero error?
here's the answer taken from :
http://www.sqlservercentral.com/Forums/Topic442497-150-1.aspx#bm1115960
Another option (especially if you've got a report with many expressions that could result in divide by zero situations is to use a Custom Code function.
In the Code tab/window of Report Properties, enter something like the following:
Public Function DivideBy(ByVal Exp1, ByVal Exp2)
If Exp2 = 0 Then
DivideBy = 0
Else : DivideBy = Exp1 / Exp2
End If
End Function
Then insert the expression
=code.DivideBy(Field!ToBeDivided.Value,Field!DividingBy.Value)
into any cell that has the potential for divide by zero problems.
Yes, both the true and false parts of an IIf function get evaluated:
http://en.wikipedia.org/wiki/IIf#Side_Effects
Side Effects
Another issue with IIf arises because it is a library
function: unlike the C-derived conditional operator, both truepart and
the falsepart will be evaluated regardless of which one is actually
returned. Consider the following example:
value = 10
result = IIf(value = 10, TrueFunction, FalseFunction)
Although TrueFunction is the function intended to be called, IIf will
cause both TrueFunction and FalseFunction to be executed.
Also consider this one:
a = 10
b = 0
result = IIf(b <> 0, a / b, 0)
While the programmer
intends to avoid raising an error by performing a division by zero,
whenever b is zero the error will actually happen. This is because the
code in the snippet is to be read as
a = 10 b = 0
_temp1 = a / b ' Error if b = 0
_temp2 = 0
_temp3 = b <> 0 result = IIf(_temp3, _temp1 , _temp2)
This issue makes
the IIf() call less useful than the conditional operator. To solve
this issue, Microsoft developers had considered converting IIf to
an intrinsic function; had this happened, the compiler would have been
able to perform type inference and short-circuiting by replacing the
function call with inline code.
Both Iif() and Switch() are function calls, so any parameters passed to them will be evaluated. They do not have the ability to short-circuit.
IIF is a function, and all the arguments to a function are evaluated before being the function itself is evaluated.
To prevent this issue, you will need to use a full If/Else statement.
Also related, if you're used to short-circuit evaluation of your boolean expressions (eg && in C-derived languages) you need to use AndAlso and OrElse in VB.Net.
In the case of an IIF statement in VB, I think everything gets evaluated, irrespective of the initial condition. This is something that has to be worked around in IIF statements.
In the second statement, the Fields!Field**2**.Value from the first IIF statement has become Fields!Field**s**.Value. Its possible that the error in that statement is failing because of that as .Value will cause an error if Fields!Fields is nothing
I tried to reproduce this error in RS 2005 and I can't! I took the following dataset:
select 5 as field1, 0 as field2
union
select 10 as field1, 5 as field2
union
select null as field1, 5 as field2
union
select 3 as field1, null as field2
union
select null as field1, null as field2
union
select 0 as field1, null as field2
union
select null as field1, 0 as field2
union
select 11 as field1, 10 as field2
union
select PI() as field1, 0 as field2
union
select PI() as field1, PI() as field2
and used your expressions, with Jon Egerton's correction in the switch. I then did a pure no-checked division.
Both your expressions worked, and even when I divide by 0 I get "Infinity" or "Nan", but not #Error.
What happens if you replace your division by 1/0. Do you get #Error or do you get Infinity?

Specify order of (T)SQL execution

I have seen similar questions asked elsewhere on this site, but more in the context of optimization.
I am having an issue with the order of execution of the conditions in a WHERE clause. I have a field which stores codes, most of which are numeric but some of which contain non-numeric characters. I need to do some operations on the numeric codes which will cause errors if attempted on non-numeric strings. I am trying to do something like
WHERE isnumeric(code) = 1
AND CAST(code AS integer) % 2 = 1
Is there any way to make sure that the isnumeric() executes first? If it doesn't, I get an error...
Thanks in advance!
The only place order of evaluation is guaranteed is CASE
WHERE
CASE WHEN isnumeric(code) = 1
THEN CAST(code AS integer) % 2
END = 1
Also just because it passes the isnumeric test doesn't guarantee that it will successfully cast to an integer.
SELECT ISNUMERIC('$') /*Returns 1*/
SELECT CAST('$' AS INTEGER) /*Fails*/
Depending upon your needs you may find these alternatives preferable.
Why not simply do it using LIKE?:
Where Code Not Like '%[^0-9]%'
Btw, either using my solution or using IsNumeric, there are some edge cases which might lead one to using a UDF such as 1,234,567 where IsNumeric will return 1 but Cast will throw an exception.
Why not use a CASE statement to say something like:
WHERE
CASE WHEN isnumeric(code) = 1
THEN CAST(code AS int) % 2 = 1
ELSE /* What ever else if not numeric */ END
You could do it in a case statement in the select clause, then limit by the value in an outer select
select * from (
select
case when isNum = 1 then CAST(code AS integer) % 2 else 0 end as castVal
from (
select
Case when isnumeric(code) = 1 then 1 else 0 end as isNum
from table) t
) t2
where castval = 1