Significance of 1e8 in divisions - sql

I am trying to understand a small function call in SQL Server 2012. I tried to search for it online but could not find much info.
The function itself is simple. It has two parameters #value and #default, both being int. This function DivFix returns #default when #value is null or 0, else it returns the #value itself.
This function is called in various SQL statements to avoid divide by zero error.
Select col1 / DivFix(col2,1e8)
My question is, what does 1e8 stand for here, and how does it help in overcoming the divide by zero error?

It means 10^8 (10 power 8), thus 100000000.
It's a short for "power(10, 8)"
From a mathematical point of view, it's not really a great way to handle "divide by 0" issue IMHO.
It would have more sense to use a very little number (which returns something close to infinite rather than a NaN / a failure) instead of this very big one (which makes the calculus return "something close to 0 but not exactly", unless the final rounding makes it equal to 0).

xEy is a common short hand for x * 10^y. So 2e8 = 2 * 10^8.
As to how it helps with divide by zero or null: I have no idea what your requirement is. x/0 isn't a valid math operation. In calculus, the result can either be positive infinity of negative infinity, depending on how you approach 0.
The current intention seems to be make the result a very small number. So why not define a constant or just set the result to 0:
DECLARE #VerySmallNumber float = 1E-8 -- ha! the exponent can be negative too
SELECT IIF(col2 = 0 OR col2 IS NULL, #VerySmallNumber, col1 / col2)

Related

Maths Rules in Kotlin

I'm trying to depreciate the value of an item in a straight line over time
If I use itemValue2 = itemvalue1 - itemvalue1*item-Age/item-Life, It works perfectly BUT when I originally
used itemValue2 = itemvalue1 * ( 1 - item-Age/item-Life) it constantly evaluated to itemValue1 .
Why would this be ? is it the type of the number 1 ?
itemValue1 and itemValue2 are Doubles, item-Age and item-Life are Longs
Or is it some maths rule that I haven't understood?
Like mentioned in the comments, Longs that divide will result in a truncated Long value. If your resulting value would've been been less than 1, then the result is a truncated value of 0. That leaves itemValue1 to be multiplied by 1, which is itself. You will have to cast to number types that use decimals without truncating like Double or Float.
This thing called Mathematical precedence in kotlin, mean when you create operation like this 1+2*3 the expected result is 9 but not, 7 is the result, in kotlin be the priority for the multiply's * and the divide's / then came the plus + and minus -.
To resolve this issue you need to add the brackets () it's had priority before any operation symbol in the language.
And the operation will be (1+2)*3it will gave result 9.

How to fix the “divide by zero” error in SQL? [duplicate]

I have this error message:
Msg 8134, Level 16, State 1, Line 1 Divide by zero error encountered.
What is the best way to write SQL code so that I will never see this error message again?
I could do either of the following:
Add a where clause so that my divisor is never zero
Or
I could add a case statement, so that there is a special treatment for zero.
Is the best way to use a NULLIF clause?
Is there better way, or how can this be enforced?
In order to avoid a "Division by zero" error we have programmed it like this:
Select Case when divisor=0 then null
Else dividend / divisor
End ,,,
But here is a much nicer way of doing it:
Select dividend / NULLIF(divisor, 0) ...
Now the only problem is to remember the NullIf bit, if I use the "/" key.
In case you want to return zero, in case a zero devision would happen, you can use:
SELECT COALESCE(dividend / NULLIF(divisor,0), 0) FROM sometable
For every divisor that is zero, you will get a zero in the result set.
This seemed to be the best fix for my situation when trying to address dividing by zero, which does happen in my data.
Suppose you want to calculate the male–female ratios for various school clubs, but you discover that the following query fails and issues a divide-by-zero error when it tries to calculate ratio for the Lord of the Rings Club, which has no women:
SELECT club_id, males, females, males/females AS ratio
FROM school_clubs;
You can use the function NULLIF to avoid division by zero. NULLIF compares two expressions and returns null if they are equal or the first expression otherwise.
Rewrite the query as:
SELECT club_id, males, females, males/NULLIF(females, 0) AS ratio
FROM school_clubs;
Any number divided by NULL gives NULL, and no error is generated.
You can also do this at the beginning of the query:
SET ARITHABORT OFF
SET ANSI_WARNINGS OFF
So if you have something like 100/0 it will return NULL. I've only done this for simple queries, so I don't know how it will affect longer/complex ones.
You can at least stop the query from breaking with an error and return NULL if there is a division by zero:
SELECT a / NULLIF(b, 0) FROM t
However, I would NEVER convert this to Zero with coalesce like it is shown in that other answer which got many upvotes. This is completely wrong in a mathematical sense, and it is even dangerous as your application will likely return wrong and misleading results.
SELECT Dividend / ISNULL(NULLIF(Divisor,0), 1) AS Result from table
By catching the zero with a nullif(), then the resulting null with an isnull() you can circumvent your divide by zero error.
EDIT:
I'm getting a lot of downvotes on this recently...so I thought I'd just add a note that this answer was written before the question underwent it's most recent edit, where returning null was highlighted as an option...which seems very acceptable. Some of my answer was addressed to concerns like that of Edwardo, in the comments, who seemed to be advocating returning a 0. This is the case I was railing against.
ANSWER:
I think there's an underlying issue here, which is that division by 0 is not legal. It's an indication that something is fundementally wrong. If you're dividing by zero, you're trying to do something that doesn't make sense mathematically, so no numeric answer you can get will be valid. (Use of null in this case is reasonable, as it is not a value that will be used in later mathematical calculations).
So Edwardo asks in the comments "what if the user puts in a 0?", and he advocates that it should be okay to get a 0 in return. If the user puts zero in the amount, and you want 0 returned when they do that, then you should put in code at the business rules level to catch that value and return 0...not have some special case where division by 0 = 0.
That's a subtle difference, but it's important...because the next time someone calls your function and expects it to do the right thing, and it does something funky that isn't mathematically correct, but just handles the particular edge case it's got a good chance of biting someone later. You're not really dividing by 0...you're just returning an bad answer to a bad question.
Imagine I'm coding something, and I screw it up. I should be reading in a radiation measurement scaling value, but in a strange edge case I didn't anticipate, I read in 0. I then drop my value into your function...you return me a 0! Hurray, no radiation! Except it's really there and it's just that I was passing in a bad value...but I have no idea. I want division to throw the error because it's the flag that something is wrong.
Replacing "divide by zero" with zero is controversial - but it's also not the only option. In some cases replacing with 1 is (reasonably) appropriate. I often find myself using
ISNULL(Numerator/NULLIF(Divisor,0),1)
when I'm looking at shifts in scores/counts, and want to default to 1 if I don't have data. For example
NewScore = OldScore * ISNULL(NewSampleScore/NULLIF(OldSampleScore,0),1)
More often than not, I've actually calculated this ratio somewhere else (not least because it can throw some very large adjustment factors for low denominators. In this case I'd normally control for OldSampleScore is greater than a threshold; which then precludes zero. But sometimes the 'hack' is appropriate.
I wrote a function a while back to handle it for my stored procedures:
print 'Creating safeDivide Stored Proc ...'
go
if exists (select * from dbo.sysobjects where name = 'safeDivide') drop function safeDivide;
go
create function dbo.safeDivide( #Numerator decimal(38,19), #divisor decimal(39,19))
returns decimal(38,19)
begin
-- **************************************************************************
-- Procedure: safeDivide()
-- Author: Ron Savage, Central, ex: 1282
-- Date: 06/22/2004
--
-- Description:
-- This function divides the first argument by the second argument after
-- checking for NULL or 0 divisors to avoid "divide by zero" errors.
-- Change History:
--
-- Date Init. Description
-- 05/14/2009 RS Updated to handle really freaking big numbers, just in
-- case. :-)
-- 05/14/2009 RS Updated to handle negative divisors.
-- **************************************************************************
declare #p_product decimal(38,19);
select #p_product = null;
if ( #divisor is not null and #divisor <> 0 and #Numerator is not null )
select #p_product = #Numerator / #divisor;
return(#p_product)
end
go
Add a CHECK constraint that forces Divisor to be non-zero
Add a validator to the form so that the user cannot enter zero values into this field.
For update SQLs:
update Table1 set Col1 = Col2 / ISNULL(NULLIF(Col3,0),1)
There is no magic global setting 'turn division by 0 exceptions off'. The operation has to to throw, since the mathematical meaning of x/0 is different from the NULL meaning, so it cannot return NULL.
I assume you are taking care of the obvious and your queries have conditions that should eliminate the records with the 0 divisor and never evaluate the division. The usual 'gotcha' is than most developers expect SQL to behave like procedural languages and offer logical operator short-circuit, but it does NOT. I recommend you read this article: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html
Here is a situation where you can divide by zero. The business rule is that to calculate inventory turns, you take cost of goods sold for a period, annualize it. After you have the annualized number, you divide by the average inventory for the period.
I'm looking at calculating the number of inventory turns that occur in a three month period. I have calculated that I have Cost of Goods sold during the three month period of $1,000. The annual rate of sales is $4,000 ($1,000/3)*12. The beginning inventory is 0. The ending inventory is 0. My average inventory is now 0. I have sales of $4000 per year, and no inventory. This yields an infinite number of turns. This means that all my inventory is being converted and purchased by customers.
This is a business rule of how to calculate inventory turns.
CREATE FUNCTION dbo.Divide(#Numerator Real, #Denominator Real)
RETURNS Real AS
/*
Purpose: Handle Division by Zero errors
Description: User Defined Scalar Function
Parameter(s): #Numerator and #Denominator
Test it:
SELECT 'Numerator = 0' Division, dbo.fn_CORP_Divide(0,16) Results
UNION ALL
SELECT 'Denominator = 0', dbo.fn_CORP_Divide(16,0)
UNION ALL
SELECT 'Numerator is NULL', dbo.fn_CORP_Divide(NULL,16)
UNION ALL
SELECT 'Denominator is NULL', dbo.fn_CORP_Divide(16,NULL)
UNION ALL
SELECT 'Numerator & Denominator is NULL', dbo.fn_CORP_Divide(NULL,NULL)
UNION ALL
SELECT 'Numerator & Denominator = 0', dbo.fn_CORP_Divide(0,0)
UNION ALL
SELECT '16 / 4', dbo.fn_CORP_Divide(16,4)
UNION ALL
SELECT '16 / 3', dbo.fn_CORP_Divide(16,3)
*/
BEGIN
RETURN
CASE WHEN #Denominator = 0 THEN
NULL
ELSE
#Numerator / #Denominator
END
END
GO
Filter out data in using a where clause so that you don't get 0 values.
Sometimes, 0 might not be appropriate, but sometimes 1 is also not appropriate. Sometimes a jump from 0 to 100,000,000 described as 1 or 100-percent change might also be misleading. 100,000,000 percent might be appropriate in that scenario. It depends on what kind of conclusions you intend to draw based on the percentages or ratios.
For example, a very small-selling item moving from 2-4 sold and a very large-selling item changing from 1,000,000 to 2,000,000 sold might mean very different things to an analyst or to management, but would both come through as 100% or 1 change.
It might be easier to isolate NULL values than to scour over a bunch of 0% or 100% rows mixed with legitimate data. Often, a 0 in the denominator can indicate an error or missing value, and you might not want to just fill in an arbitrary value just to make your dataset look tidy.
CASE
WHEN [Denominator] = 0
THEN NULL --or any value or sub case
ELSE [Numerator]/[Denominator]
END as DivisionProblem
This is how I fixed it:
IIF(ValueA != 0, Total / ValueA, 0)
It can be wrapped in an update:
SET Pct = IIF(ValueA != 0, Total / ValueA, 0)
Or in a select:
SELECT IIF(ValueA != 0, Total / ValueA, 0) AS Pct FROM Tablename;
Thoughts?
You can handle the error appropriately when it propagates back to the calling program (or ignore it if that's what you want). In C# any errors that occur in SQL will throw an exception that I can catch and then handle in my code, just like any other error.
I agree with Beska in that you do not want to hide the error. You may not be dealing with a nuclear reactor but hiding errors in general is bad programming practice. This is one of the reasons most modern programming languages implement structured exception handling to decouple the actual return value with an error / status code. This is especially true when you are doing math. The biggest problem is that you cannot distinguish between a correctly computed 0 being returned or a 0 as the result of an error. Instead any value returned is the computed value and if anything goes wrong an exception is thrown. This will of course differ depending on how you are accessing the database and what language you are using but you should always be able to get an error message that you can deal with.
try
{
Database.ComputePercentage();
}
catch (SqlException e)
{
// now you can handle the exception or at least log that the exception was thrown if you choose not to handle it
// Exception Details: System.Data.SqlClient.SqlException: Divide by zero error encountered.
}
Use NULLIF(exp,0) but in this way - NULLIF(ISNULL(exp,0),0)
NULLIF(exp,0) breaks if exp is null but NULLIF(ISNULL(exp,0),0) will not break

Why is SQL Server changing operation order and boxing the way it does?

Four simple SELECT statements:
SELECT 33883.50 * -1;
SELECT 33883.50 / -1.05;
SELECT 33883.50 * -1 / 1.05;
SELECT (33883.50 * -1) / 1.05;
But the results are not as I would expect:
-33883.50
-32270.000000
-32269.96773000
-32270.000000
That third result is the one that seems questionable. I can see what is happening, first SQL Server evaluates this:
SELECT -1 / 1.05;
Getting an answer of:
-0.952380
Then it takes that answer and uses it to perform this calculation:
SELECT 33883.50 * -0.952380;
To get the (wrong) answer of:
-32269.96773000
But why is it doing this?
In your example
33883.50 * -1 / 1.05
is evaluated as
33883.50 * (-1 / 1.05)
instead of
(33883.50 * -1) / 1.05
which results in a loss in precision.
I played a bit with it. I used SQL Sentry Plan Explorer to see the details of how SQL Server evaluates expressions. For example,
2 * 3 * -4 * 5 * 6
is evaluated as
((2)*(3)) * ( -((4)*(5))*(6))
I'd explain it like this. In T-SQL unary minus is made to be the same priority as subtraction, which is lower than multiplication. Yes,
When two operators in an expression have the same operator precedence
level, they are evaluated left to right based on their position in the
expression.
, but here we have an expression that mixes operators with different priorities and parser follows these priorities to the letter. Multiplication has to go first, so it evaluates 4 * 5 * 6 at first and then applies unary minus to the result.
Normally (say in C++) unary minus has higher priority (like bitwise NOT) and such expressions are parsed and evaluated as expected. They should have made unary minus/plus same highest priority as bitwise NOT in T-SQL, but they didn't and this is the result. So, it is not a bug, but a bad design decision. It is even documented, though quite obscurely.
When you refer to Oracle - that the same example works differently in Oracle than in SQL Server:
Oracle may have different rules for operator precedence than SQL Server. All it takes is to make unary minus highest priority as it should.
Oracle may have different rules for determining result precision and scale when evaluating expressions with decimal type.
Oracle may have different rules for rounding intermediate results. SQL Server "uses rounding when converting a number to a decimal or numeric value with a lower precision and scale".
Oracle may be using completely different types for these kind of expressions, not decimal. In SQL Server "a constant with a decimal point is automatically converted into a numeric data value, using the minimum precision and scale necessary. For example, the constant 12.345 is converted into a numeric value with a precision of 5 and a scale of 3."
Even definition of decimal may be different in Oracle. Even in SQL Server "the default maximum precision of numeric and decimal data types is 38. In earlier versions of SQL Server, the default maximum is 28."
Do you know BODMAS rule. The answer is correct its not because of Sql Server, Its a basic mathematics.
First comes Division then comes the Subtraction, So always Division will happen before Subtraction
If you want to get correct answer then use proper parenthesis
SELECT (33883.50 * -1) / 1.05;
T-SQL has an rule for operator precedence which it follows. You can read about it on the link https://msdn.microsoft.com/en-us/library/ms190276.aspx.
It seems to be a precedence rule concerning unary operators. I have tried the following queries
SELECT 33883.50 * cast(-1 as int) / 1.05;
SELECT 33883.50 * (-1 * 1) / 1.05;
and it returns the right answer. The best thing to do is to use parentheses on expressions you want to occur first, and test thoroughly.

Why is null * 0 = null in sql when it is not in math or other languages

Why is 'null * 0 = null'?
There can not be any other result, why is null*0 not evaluated to 0?
Is it possible that this has to do with some higher level math which i am unfamiliar with, or would it may be have some implications for the dbms?
It's a sane design choice to maintain NULLness through all manners of operation. Making an exception for multiplication by 0 would raise inconsistencies, e.g.
0 * NULL; # 0
1 * NULL; # NULL
.5 * NULL; # HALFNULL? ;-)
NULL in SQL represents "unknown". When a math operation is performed with an unknown, you could not possibly get anything known, even when you multiply it by zero. Similar situation happens in math: although multiplying any number by zero yields zero, multiplying an infinity by zero doesn't.
It's simply part of the ANSI standard. Some cases can be overriden on some systems (for example, comparing nulls on MS SQL).
All in all, it's about avoiding undefined behaviour. What should null * 0 give? What type is the null? There's just too many things that can kill predictability. In programming, null is mostly handled as a special value, and for good reasons - I don't know is something else than No, after all :) Of course, Objective-C designers wouldn't agree with me... :D
As for what this has to do with math, well, null isn't a real number, obviously, so null * 0 would be undefined for real numbers. You'd have to have a "bigger" number category that would contain your null, and it would have to have the * operation redefined (or not). When you're dealing with math, don't forget the constraints - rules like A * 0 = 0 only apply inside their number categories. Infinity * 0 is not 0 - it's undefined.

Strange behavior while rounding in SQL server 2008

At some point I have a numeric(28,10) and I cast it in money (I know its bad but for legacy reason I have to return money) in the same time I also have to set the sign (multiplying by +1/-1).
In a first attempt I had cast the +/-1 to match the numeric type.
For the value 133.3481497944 we encounter a strange behavior (I have simplified the actual code in order to keep only the elements needed to demonstrate the problem):
SELECT CAST(CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(28,10)) AS money)
133.3482
which is not correctly rounded...
Removing the cast solve the problem
SELECT CAST(CAST(133.3481497944 AS numeric(28,10)) * 1 AS money)
133.3481
Did someone know what is happening in SQL? How can a multiplication by 1 and cast(1 AS numeric(28,10)) affect the result of the rounding?
When multiplying numerics, SQL uses the following rules to determine the precision and scale of the output:
p = p1 + p2 + 1
s = s1 + s2
which makes sense - you wouldn't want 1.5 * 2.5 to be truncated to one digit past the decimal. Nor would you want 101 * 201 to be limited to 3 digits of precision, giving you 20300 instead of 20301.
In your case that would result in a precision of 57 and a scale of 20, which isn't possible - the maximum precision and scale is 38.
If the resulting type is too big, decimal digits are sacrificed in order to preserve the integral (most significant) part of the result.
From the SQL Programmability & API Development Team Blog:
In SQL Server 2005 RTM (and previous versions), we decided preserve a minimum scale of 6 in both multiplication and division.
So your answer depands on how big and precise you need the multiplier to be. In order to preserve 10 digits of decimal precision. If the multiplier needs a scale bigger than 9, then decimal digits may be truncated. If you use a smaller precision and scale, you should be fine:
SELECT CAST(CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(9,7)) AS money)
yields 133.3481.
I don't see any ROUNDing here. I only see casting. Don't assume that it will round, when you CAST. Historically, when we cast the environment truncates (SQL server or not) or behaves not as we expect - especially when we're talking about FLOATs.
SELECT
CAST(CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(28,10)) AS money) --Your original,
CAST(1 AS numeric(28,10)) --Just the 1 casted,
CAST(133.3481497944 AS numeric(28,10)) --Your expected calculation,
CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(28,10)) -- The actual calculation
SELECT
CAST(133.3481497944 AS numeric(28,10))*cast(1.5 AS numeric(28,10)),
CAST(133.3481497944 AS numeric(28,10))*1.5,
CAST((133.3481497944*1) AS money),
133.3481497944*1
Returns
133.3482
1.0000000000
133.3481497944
133.348150
200.022225
200.02222469160
133.3481
133.3481497944
So as mentioned above, there really isn't any true rounding, but a loss of precision during the cast. As to exactly why, I don't know. Most likely during the calculation(multiplication) while using the Numeric(28,10) it cuts off some precision.
I added the second lines to show that really you may not need your numeric casting.