Some times you may want to select rows from some table and in each row you would like to have some random number generated. You may want to try the RAND()
function. However, it will generate a random number, all the returned rows will have the same random number and this is mostly not what you intended.
SELECT TOP 10 RAND() FROM sys.all_columns
Running the above query you will receive.
---------------------- 0,173895240378828 0,173895240378828 0,173895240378828 0,173895240378828 0,173895240378828 0,173895240378828 0,173895240378828 0,173895240378828 0,173895240378828 0,173895240378828 (10 row(s) affected)
This is caused because the RAND()
function is a constant function and the constant function is executed once on the query start, and then the value is used everywhere in the query. There are more functions in SQL Server, that behave as Constant Expressions and which are executed once per the whole Query e.g. the GETDATE()
function.
Whether the function is a executed as constant expression or whether it is executed once per row, you can find from the XML plan for the query. If we take the a look on the XML plan for the above query we will see:
<?xml version="1.0" encoding="utf-16"?> <ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1" Build="10.50.1600.1" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"> <BatchSequence> <Batch> <Statements> <StmtSimple StatementCompId="1" StatementEstRows="10" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" StatementSubTreeCost="0.00346253" StatementText="SELECT TOP 10
 RAND()
FROM sys.all_columns" StatementType="SELECT" QueryHash="0x479AE6BF06344217" QueryPlanHash="0x1960EA8D4F47E514"> <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" /> <QueryPlan CachedPlanSize="32" CompileTime="3" CompileCPU="3" CompileMemory="544"> <RelOp AvgRowSize="15" EstimateCPU="1E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="10" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="0.00346253"> <OutputList> <ColumnReference Column="Expr1063" /> </OutputList> <ComputeScalar> <DefinedValues> <DefinedValue> <ColumnReference Column="Expr1063" /> <ScalarOperator ScalarString="rand()"> <Identifier> <ColumnReference Column="ConstExpr1065"> <ScalarOperator> <Intrinsic FunctionName="rand"> <ScalarOperator> <Const ConstValue="" /> </ScalarOperator> </Intrinsic> </ScalarOperator> </ColumnReference> </Identifier> </ScalarOperator> </DefinedValue> </DefinedValues> <RelOp AvgRowSize="9" EstimateCPU="1E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="10" LogicalOp="Top" NodeId="1" Parallel="false" PhysicalOp="Top" EstimatedTotalSubtreeCost="0.00346153"> <OutputList /> <Top RowCount="false" IsPercent="false" WithTies="false"> <TopExpression> <ScalarOperator ScalarString="(10)"> <Const ConstValue="(10)" /> </ScalarOperator> </TopExpression> <RelOp AvgRowSize="9" EstimateCPU="0.000515516" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="10" LogicalOp="Concatenation" NodeId="2" Parallel="false" PhysicalOp="Concatenation" EstimatedTotalSubtreeCost="0.00346053"> <OutputList /> <Concat> <DefinedValues /> <RelOp AvgRowSize="9" EstimateCPU="0.00083584" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="10" LogicalOp="Filter" NodeId="3" Parallel="false" PhysicalOp="Filter" EstimatedTotalSubtreeCost="0.00337579"> <OutputList /> <Filter StartupExpression="false"> <RelOp AvgRowSize="13" EstimateCPU="0.0008753" EstimateIO="0.0068287" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="10" LogicalOp="Index Scan" NodeId="4" Parallel="false" PhysicalOp="Index Scan" EstimatedTotalSubtreeCost="0.00335999" TableCardinality="653"> <OutputList> <ColumnReference Database="[TestDB]" Schema="[sys]" Table="[syscolpars]" Column="id" /> </OutputList> <IndexScan Ordered="false" ForcedIndex="false" ForceSeek="false" NoExpandHint="false"> <DefinedValues> <DefinedValue> <ColumnReference Database="[TestDB]" Schema="[sys]" Table="[syscolpars]" Column="id" /> </DefinedValue> </DefinedValues> <Object Database="[TestDB]" Schema="[sys]" Table="[syscolpars]" Index="[nc]" IndexKind="NonClustered" /> <Predicate> <ScalarOperator ScalarString="[TestDB].[sys].[syscolpars].[number]=(0)"> <Compare CompareOp="EQ"> <ScalarOperator> <Identifier> <ColumnReference Database="[TestDB]" Schema="[sys]" Table="[syscolpars]" Column="number" /> </Identifier> </ScalarOperator> <ScalarOperator> <Const ConstValue="(0)" /> </ScalarOperator> </Compare> </ScalarOperator> </Predicate> </IndexScan> </RelOp> <Predicate> <ScalarOperator ScalarString="has_access('CO',[TestDB].[sys].[syscolpars].[id])=(1)"> <Compare CompareOp="EQ"> <ScalarOperator> <Intrinsic FunctionName="has_access"> <ScalarOperator> <Const ConstValue="'CO'" /> </ScalarOperator> <ScalarOperator> <Identifier> <ColumnReference Database="[TestDB]" Schema="[sys]" Table="[syscolpars]" Column="id" /> </Identifier> </ScalarOperator> <ScalarOperator> <Const ConstValue="" /> </ScalarOperator> <ScalarOperator> <Const ConstValue="" /> </ScalarOperator> </Intrinsic> </ScalarOperator> <ScalarOperator> <Const ConstValue="(1)" /> </ScalarOperator> </Compare> </ScalarOperator> </Predicate> </Filter> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="0.0132712" EstimateIO="0.0749769" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Index Scan" NodeId="6" Parallel="false" PhysicalOp="Index Scan" EstimatedTotalSubtreeCost="0.00329434" TableCardinality="11922"> <OutputList /> <IndexScan Ordered="false" ForcedIndex="false" ForceSeek="false" NoExpandHint="false"> <DefinedValues /> <Object Database="[mssqlsystemresource]" Schema="[sys]" Table="[syscolrdb]" Index="[ncl]" IndexKind="NonClustered" /> <Predicate> <ScalarOperator ScalarString="[mssqlsystemresource].[sys].[syscolrdb].[number]=(0)"> <Compare CompareOp="EQ"> <ScalarOperator> <Identifier> <ColumnReference Database="[mssqlsystemresource]" Schema="[sys]" Table="[syscolrdb]" Column="number" /> </Identifier> </ScalarOperator> <ScalarOperator> <Const ConstValue="(0)" /> </ScalarOperator> </Compare> </ScalarOperator> </Predicate> </IndexScan> </RelOp> </Concat> </RelOp> </Top> </RelOp> </ComputeScalar> </RelOp> </QueryPlan> </StmtSimple> </Statements> </Batch> </BatchSequence> </ShowPlanXML>
On the line 19 or the Query you can see ConstExpr1065
under the node of <ScalarOperator ScalarString="rand()">
. Each function which is in the XML plan expressed in the ColumnReference as ConstExpr is executed as constant function once per whole query.
Workaround for RAND function
As a workaround for generating the random numbers in a query, it is possible to use the NEWID()
function. Although it the return value of the function is uniqueidentifier, every call to the function return a new unique value, which we can use a CHECKSUM()
function over it which calculates checksum of an expression the checksum is an integer value. Because the value can be negative or positive it is necessary to use ABS()
over it to receive consistent values.
So finally we can write following query:
SELECT TOP 10 ABS(CHECKSUM(NEWID())) AS Random, ABS(CHECKSUM(NEWID())) % 100 AS Random_0_100, CAST(CHECKSUM(NEWID()) & 0x7fffffff AS float) / CAST(0x7fffffff as int) AS RandomFloatValue FROM sys.all_objects
And the result will be similar to the one below where each value is unique random number.
Random Random_0_100 RandomFloatValue ----------- ------------ ---------------------- 1060745673 73 0,290147927724825 1053300815 99 0,835112006792385 1233927720 13 0,551734537608798 1059863691 70 0,316186188401741 495435569 98 0,770220997636309 1364620416 82 0,404617617095177 783618590 58 0,161057420615599 1176654027 15 0,522251577825403 1871862272 0 0,295878297321442 1870125345 10 0,0176546154625968 (10 row(s) affected)