admin

随机选择并不总是返回单行

sql

遵循(简化)代码片段的目的是返回 一个随机行 。不幸的是,当我们在查询分析器中运行此片段时,它返回的结果介于零到三个之间。

由于我们的输入表正好由5个具有唯一ID的行组成,并且当我们在此表上执行ID 等于 随机数的选择时,我们感到困惑的是,返回的行将不止一个。

注意:除其他外,我们已经尝试过将校验和结果转换为无用的整数。

DECLARE @Table TABLE (
  ID INTEGER IDENTITY (1, 1)
  , FK1 INTEGER
)

INSERT INTO @Table
SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5

SELECT  *
FROM    @Table 
WHERE   ID = ABS(CHECKSUM(NEWID())) % 5 + 1

编辑

我们的使用场景如下所示(请不要评论是否做正确的事。这是决定的力量)

最终,我们必须创建一个具有 实际 值的结果,通过从表本身中随机选择现有的权重来 混淆 生产者和权重的组合。
然后查询将变成这样(也是RAND无法使用的原因)

SELECT  t.ID
        , FK1 = (SELECT FK1 FROM @Table WHERE ID=ABS(CHECKSUM(NEWID())) % 5 + 1)
FROM    @Table t

因为内部选择可能返回零结果,所以它将再次返回NULL值,这是不可接受的。究其原因,是内部选择为什么在零和x结果之间返回的调查(这甚至是英语吗?)。

回答

对我来说,亮起的ABS(CHECKSUM(NEWID())) % 5 + 1)是对 每一行
进行了重新评估的简单观察。我的印象是,ABS(CHECKSUM(NEWID())) % 5 + 1)应该先评估 一次 ,然后再进行匹配。

谢谢大家的回答,虽然缓慢但确实可以使我更好地理解。


阅读 136

收藏
2021-06-07

共1个答案

admin

发生这种情况的原因是因为NEWID()为表中的每一行提供了不同的值。对于每一行, 独立于其他行
,有五分之一的机会将其返回。因此,就目前而言,实际上所有5行返回的概率为3125分之一!

要查看此信息,请运行以下查询。您会看到每一行都有一个不同的ID。

SELECT  * , NEWID()
FROM    @Table

这将修复您的代码:

DECLARE @Id int
SET @Id = ABS(CHECKSUM(NEWID())) % 5 + 1

SELECT  * 
FROM    @Table  
WHERE   ID = @Id

但是,我不确定这是从表中选择单个随机行的最有效方法。

您可能会发现此MSDN文章很有用:http :
//msdn.microsoft.com/zh-cn/library/Aa175776(T-SQL中的随机抽样)

编辑1 :现在我考虑一下, 假设行数保持固定并且ID保证是连续的 ,这可能是最有效的方法。

编辑2 :当用作子查询时,要获得所需的结果,请使用TOP 1,如下所示:

SELECT  t.ID 
        , FK1 = (SELECT TOP 1 FK1 FROM @Table ORDER BY NEWID()) 
FROM    @Table t
2021-06-07