为什么tsql Rand函数在where子句中不起作用?

时间:2013-11-17 20:42:04

标签: sql sql-server tsql random

我试图从表中随机选择一行。我很好奇为什么下面的两个陈述不起作用:

select LastName from DataGeneratorNameLast where id = (ABS(CHECKSUM(NewId())) % 3)+1

select LastName from DataGeneratorNameLast where id = cast(Ceiling(RAND(convert(varbinary, newid())) *4) as int)

两个语句随机返回1行,无行或多行。对于我的生活,我无法弄清楚为什么。只在查询中添加前1只能解决多行的问题 - 但不会返回任何行。

是的我可以通过选择top 1并按newid()排序来做同样的事情。但是为什么这不起作用的谜团让我发疯。

关于我为什么要多行回来的想法?

以下是我用来选择的表格:

Create Table dbo.DataGeneratorNameLast
(
[Id] [int] IDENTITY(1,1) NOT NULL,
LastName varchar(50) NOT NULL,
)
Go

insert into DataGeneratorNameLast (LastName) values ('SMITH')
insert into DataGeneratorNameLast (LastName) values ('JOHNSON')
insert into DataGeneratorNameLast (LastName) values ('Booger')
insert into DataGeneratorNameLast (LastName) values ('Tiger')

3 个答案:

答案 0 :(得分:2)

newid()会对与其进行比较的每一行进行评估,从而生成不同的数字。要做你想做的事,你应该在select之前将随机值生成一个变量,然后引用变量。

Declare @randId int = (abs(checksum(newid())) % 3) + 1;

select LastName from DataGeneratorNameLast where id = @randId;

正如马丁在评论中所说的那样。 Rand()的行为会有所不同,每次查询只会被评估一次。

答案 1 :(得分:0)

如果该表至少有一行该查询将返回一行,则必须使用一行。

select TOP (1) LastName 
from DataGeneratorNameLast 
ORDER BY NEWID()

请注意,如果表具有大量行,则此解决方案可能会很慢。

关于select LastName from DataGeneratorNameLast where id = @Rand - 此解决方案不保证存在带id的行。甚至IDENTITY列也可以包含间隙。如果您确实需要一行,请进行初步检查IF EXISTS (select * from DataGeneratorNameLast where id = @Rand) SELECT ...

答案 2 :(得分:0)

我有一个类似的问题并通过将ID作为主要密钥来修复它。

每行计算NEWID()。如果没有主键,除了表扫描之外没有访问模式,并且会针对每一行检查过滤器,因此为每一行计算不同的值,然后您会得到许多行匹配。

使用密钥,搜索可用,因此谓词计算一次并用作搜索的搜索参数。