Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Server Modulo function appears to return values outside of expected range [duplicate]

While running a modulo function inside a case statement, there are many times that a value outside of the expected range is returned.

SELECT CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL 
       ELSE 'What Happened?' END 

If you run this script a few times, you will see there are times that the result appears to be outside of the range of 0,1,2,3,4. My thinking is that this is somehow returning non-integer values during the case statement causing modulo to be an ineffective method of sorting by case.

Could someone explain what is happening in these cases so that I can combat this in the future?

NOTE: If I run the code modulo function by itself (outside of case statement) and return the results all values are in the range of 0,1,2,3,4 as expected.

like image 461
rdbradshaw Avatar asked Feb 02 '16 21:02

rdbradshaw


People also ask

What does MOD () function do in SQL?

Returns the remainder of one number divided by another.

How do I get only positive values in SQL?

To compute the absolute value of a number, use the ABS() function. This function takes a number as an argument and returns its value without the minus sign if there is one. The returned value will always be non-negative – zero for argument 0, positive for any other argument.

Does SQL have modulus?

The MOD function in standard query language (SQL) takes two arguments of numeric data type, the first argument as dividend and second argument as divisor and returns the remainder or modulus after performing a division operation or repeated subtraction. It is similar to REMAINDER and FLOOR functions.


1 Answers

Change your statement to

SELECT top(1)
 CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL 
       ELSE 'What Happened?' END 

And have a look at the actual execution plan.

The IN part in the case is expanded to.

CASE WHEN abs(checksum(newid()))%(5)=(4) OR 
          abs(checksum(newid()))%(5)=(3) OR 
          abs(checksum(newid()))%(5)=(2) OR 
          abs(checksum(newid()))%(5)=(1) OR 
          abs(checksum(newid()))%(5)=(0) 
  THEN NULL 
  ELSE 'What Happened?' 
END

abs(checksum(newid()))%(5) is executed once for each value in the in clause.

like image 100
Mikael Eriksson Avatar answered Oct 12 '22 22:10

Mikael Eriksson