Jeff Smith Blog

Random Thoughts & Cartesian Products with Microsoft SQL Server

Returning Random Numbers in a SELECT statement

As it is implemented, the RAND() function in SQL Server doesn't let you return a different random number per row in your SELECT statement. For example, if you execute this:

SELECT Rand() as RandomNumber, *
FROM Northwind..Customers

You will see the same number over and over.  However, sometimes, you may want to return a randomly generated number per line in your SELECT.   Here's one way to do that, in SQL Server 2000, using a UDF.

First, we need to create a View that returns a single random number:

CREATE VIEW vRandNumber
AS
SELECT RAND() as RandNumber

The view is necessary because normally in a UDF we cannot use the rand() function, because that would make the function non-determistic.  We can trick the UDF to accepting a random number by using a View.

Once that is set up, we can then create our function:

CREATE FUNCTION RandNumber()
RETURNS float
AS
  BEGIN
  RETURN (SELECT RandNumber FROM vRandNumber)
  END


Finally, you can use this function in any SELECT to now return a random number between 0 and 1 per row:

SELECT dbo.RandNumber(), *
FROM Northwind..Customers

You can get even fancier in your RandNumber function by accepting a seed if you like, or allowing for range parameters like this:

CREATE FUNCTION RandNumber2(@Min int, @Max int)
RETURNS float
AS
 BEGIN
 RETURN @Min + (select RandNumber from RetRandNumber) * (@Max-@Min)
 END

Do whatever you need to do, depending on your needs.  If you have existing code that needs to generate random values per row in a table, you may have been forced to write it using cursors or an outside language like VB.  Hopefully, you will find this useful and may be able to re-write some of that using set-based operations in pure T-SQL.

I was surprised, to be honest, that SQL Server executed the function over and over for each line in the SELECT; a UDF is supposed to be deterministic by definition, and since no parameters are being passed on each call, in theory SQL Server should only need to execute the UDF once per SELECT.  However, SQL Server calls UDF over and over for each row, and that allows us to implement our custom RAND() function successfully.

Enjoy!

see also:

Legacy Comments


robvolk
2004-11-22
re: Returning Random Numbers in a SELECT statement
Jeff-

Have you tried this one yet?

SELECT CAST(CAST(newid() AS binary(4)) AS int)

It's pretty random, but needs work in controlling the range of values. Casting as binary(3), binary(2) etc. can help there.

Jeff
2004-11-22
re: Returning Random Numbers in a SELECT statement
ah! i hadn't thought of converting to binary! I was thinking of using newid() and maybe converting the hex values, but it seemed like too much work. Not bad at all -- I like it. The other thing I was thinking about was: I am not sure of the algorithm for generating a GUID -- it depends on how random the 4 bytes you are converting to an int are. I assume it should be well distributed, but it may not be -- i.e., based on some factors on your machine values x-y are very likely while values a-b are impossible, etc. But I have no idea for sure about it.

Good idea!

robvolk
2004-11-23
re: Returning Random Numbers in a SELECT statement
I can't vouch for the distribution pattern, but there are a few tweaks you can make:

SELECT rand(cast(cast(newid() as binary(4)) as int)) * cast(cast(newid() as binary(4)) as int)

or

SELECT cast(newid() as binary(4)) ^ cast(substring(cast(newid() as binary(4)), 7,4) as int)

Variations like these are sure to mix the results up enough to be about as random as you can get.

Jeff S
2004-11-24
re: Returning Random Numbers in a SELECT statement
not bad at all -- and who know if RAND() is evenly distributed anyway ???

Claes W
2004-11-29
re: Returning Random Numbers in a SELECT statement
Actually the UDF is not deterministic. So that is why SQL Server evaluates the udf for each row.

uncomment the rand() and the udf will be NonDeterministic, and reasonably so.

create view vrandnumber with schemabinding as select /*rand()*/ 1 as randnumber
go
create function randnumber() returns float with schemabinding
as begin return (select randnumber from dbo.vrandnumber) end
go

select objectproperty(object_id('RandNumber'),'IsDeterministic') as Deterministic

drop function randnumber
drop view vrandnumber
go

Jeff
2004-11-29
re: Returning Random Numbers in a SELECT statement
Thanks, Claes.

Of course this UDF is non-deterministic, that's why it works! :)

My point was that UDF's by definition are supposed to ALWAYS be deterministic; that is how they are specified and implemented in SQL Server 2000. Which is why we must use the View to "trick" SQL server into compiling and creating this UDF at all -- if we try to use a function such as RAND() or GETDATE() within a UDF, SQL Server does not allow it.

So, therefore, if SQL Server only allows deterministic functions, then a function that accepts no arguments should in theory always return the same value in a given SELECT statement. And if that is true, then it should only be evaluated ONCE. But, of course, as I mention this is not the case (luckily; otherwise, this particular piece of code would not work).

So, thanks for the feedback, but I think you misinterpreted that particular part (or more likely I did not express things very clearly).
I hope this helped clear things up for you! If you have any other questions, let me know!

- Jeff

Mathias Raacke
2005-05-30
won't work on SQL 2005
This will not work on SQL Server 2005:
"Invalid use of side-effecting or time-dependent operator"

Do you know a workaround or better solution for SQL2005?

Jeff
2005-06-01
re: SQL 2005
Ah! It appears SQL 2005 is a bit smarter than SQL 2000 and harder to trick! I haven't gotten a chance to really dig deep into SQL 2005 just yet, I'm sure there will be a way to get this done.

eeee
2005-08-22
re: Returning Random Numbers in a SELECT statement
try this it is a simple but effective way of generating random numbers in sql. select CAST((1000*rand())+1 AS INT)

Change the 1000 to any number to set a top limit to the numbers for you.

Jeff
2005-08-22
re: Returning Random Numbers in a SELECT statement
>> try this it is a simple but effective way of generating random numbers in sql. select CAST((1000*rand())+1 AS INT)

Thanks for the feedback, eee, but you've got to read the article .... that doesn't work for a multi-row select as the value returned is the same for each row. That behavior, and ways to avoid it, is the entire point of my post.

nicolas
2006-05-10
re: Returning Random Numbers in a SELECT statement
Please tell me how youde ploy it as a managed UDF in sql2000.


like this ?sp_addextendedproc 'xp_UserDefinedFunctions', 'xp_UserDefinedFunctions.dll'

Thanks

Tim Smolka
2006-06-05
re: Returning Random Numbers in a SELECT statement
In 2005 sp1, I'm finding a failure when trying to run replication; however, when I just excute the UDF it seems to work just fine.

So the data/random in view seems to still be alright, knock on keyboard.

darkeagle03
2007-07-25
re: Returning Random Numbers in a SELECT statement
Try this in 2005 (or any other SQL):

RAND(CAST(NEWID() AS BINARY(6)))

As long as you provide a seed to the RAND function it becomes non deterministic and evaluates at every row. All that you have to do is make sure that your seed changes so that you get a new number during each call. You don't really have to worry about how random the seed is because the RAND function will take care of the randomization for you.

Mike
2007-09-08
re: Returning Random Numbers in a SELECT statement
For those of you still wondering-This technique DOES work in SQL 2005.

Rod
2007-10-26
re: Returning Random Numbers in a SELECT statement
That works for me... thanks

Josh
2008-06-24
re: Returning Random Numbers in a SELECT statement
I could hug you all...this is much better than using a date to randomize

bretlowery
2008-08-26
re: Returning Random Numbers in a SELECT statement
Hi, I noticed when testing this function that the returned range of values includes the @Min value but excludes the @Max value. This may not be the effect that some would expect from the function.

To include both the @Min and @Max values in the returned range of random numbers, change "@Max-@Min" to "@Max+1-@Min" :

ALTER FUNCTION [dbo].[fnGetRandomNumber](@Min int, @Max int)
RETURNS float
AS
BEGIN
RETURN @Min + (select RandomNumber from vwRandomNumberGenerator ) * (@Max+1-@Min)
END

Nitin
2008-12-22
re: Returning Random Numbers in a SELECT statement
Thanks dear its help me although there is another site i found which makes me clear on this topic.
http://kaniks.blogspot.com/search/label/generate%20random%20number%20from%20t-sql

i hope this will help to other as well

David
2009-02-06
re: Returning Random Numbers in a SELECT statement
I am trying to do something similar, but, UPDATE one table's Names values with a table with sample names I'd like to make it random. Basically I'm trying to de-identify a patient database ith fake names. Here's my SQL, can anyone help!!!

CREATE VIEW vRandName
AS
(SELECT TOP (1) Name FROM dbo.TestNames ORDER BY NEWID() as RandName)

CREATE FUNCTION random_names()
returns nchar
AS
BEGIN
DECLARE @f nchar
SET @f = (SELECT TOP (1) Name
FROM dbo.TestNames
ORDER BY NEWID())
RETURN @f
END
go
UPDATE TBL_PATIENT
SET First_NAME = random_names()

David

Praba
2009-03-10
re: Returning Random Numbers in a SELECT statement
I use the below code to generate the unique/random id.

SELECT (DATENAME(year, getDate()) + CONVERT(VARCHAR(2),DATEPART(m, GETDATE())) + DATENAME(d, getDate()) + DATENAME(hh, getDate()) + DATENAME(mi, getDate()) + DATENAME(ss, getDate()) + DATENAME(ms, getDate()))

Patrick McCann
2009-03-25
re: Returning Random Numbers in a SELECT statement
I tested the command : RAND(CAST(NEWID() AS BINARY(6)))


The distribution of the output is certainly distributed uniform(0,1)

Perhaps the next step is to use this to develop an MCMC algorithm in SQL

Mario
2009-07-23
re: Returning Random Numbers in a SELECT statement
SELECT TOP 1 * FROM table
ORDER BY NEWID()

Andrea
2010-01-04
re: Returning Random Numbers in a SELECT statement
Thank you, it works very well. Just one thing: in the second function, RetRandNumber should be VRandNumber instead

snow boots for women
2010-10-06
re: Returning Random Numbers in a SELECT statement
Finally, you can use this function in any SELECT to now return a random number between 0 and 1 per row