【问题标题】:Why does tsql Rand function not work in where clause?为什么 tsql Rand 函数在 where 子句中不起作用?
【发布时间】:2013-11-17 20:42:04
【问题描述】:

我正在尝试从表中随机选择一行。我很好奇为什么下面的两个语句不起作用:

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')

【问题讨论】:

    标签: sql sql-server tsql random


    【解决方案1】:

    newid() 会针对与之比较的每一行进行评估,生成不同的数字。做你想做的,你应该在选择之前将随机值生成到一个变量中,然后引用该变量。

    Declare @randId int = (abs(checksum(newid())) % 3) + 1;
    
    select LastName from DataGeneratorNameLast where id = @randId;
    

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

    【讨论】:

    • 正确,但仅仅是因为 newid 种子。 rand() 本身就是 evaluated once
    • @MartinSmith 我已经试过了,可以凭经验看出你是对的。但是我在文档中看不到任何内容来理解原因。如果你想写一个不同的答案,我会删除我的。
    • 这是因为rand 被视为“运行时常量”,而newid 不是。
    • 嗨。我不想将它分配给变量。我想将此语句用作子查询来插入大量随机名称的测试/假客户数据。
    • 嗨。我仍然无法弄清楚具有“id = [MyRandomValue] 的 select 语句如何/为什么可能返回超过 1 行,其中 id 是唯一的整数集。这对我来说似乎是一个缺陷。想法。跨度>
    【解决方案2】:

    如果表至少有一行,则此查询将返回一行是强制性的。

    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 ...

    【讨论】:

    • 嗨。感谢你的回答。是的,我已经看到了那个解决方案。我不担心身份列中的空白。我无法弄清楚具有“id = [MyRandomValue] 的 select 语句如何/为什么可能返回超过 1 行,其中 id 是一个唯一的整数集。这对我来说似乎是一个缺陷。想法。跨度>
    【解决方案3】:

    我遇到了类似的问题,并通过将 ID 设为 PRIMARY KEY 来解决它。

    NEWID() 是按行计算的。如果没有主键,除了表扫描之外没有其他访问模式,并且会检查每一行的过滤器,因此为每一行计算不同的值,并且无论多少行都匹配。

    有了这个键,seek 就可用了,所以谓词只计算一次,并用作 seek 的搜索参数。

    【讨论】:

      猜你喜欢
      • 2019-07-12
      • 2023-03-21
      • 2011-11-16
      • 2017-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-24
      相关资源
      最近更新 更多