Lie*_*ers 2 sql sql-server random sql-server-2005
遵循(简化)代码片段的意图是返回一个随机行.不幸的是,当我们在查询分析器中运行此片段时,它返回0到3之间的结果.
由于我们的输入表恰好包含5行且具有唯一ID,并且当我们在此表上执行选择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
Run Code Online (Sandbox Code Playgroud)
我们的使用场景如下(请不要评论它是否是正确的做法.这是决定的权力)
最终,我们必须创建一个具有实际值的结果,其中通过从表本身随机选择现有权重来混淆生产者和权重的组合.
然后查询会变成这样(也是RAND不能使用的原因)
SELECT t.ID
, FK1 = (SELECT FK1 FROM @Table WHERE ID=ABS(CHECKSUM(NEWID())) % 5 + 1)
FROM @Table t
Run Code Online (Sandbox Code Playgroud)
因为内部选择可能返回零结果,所以它将返回NULL值,这也是不可接受的.调查内部选择为什么在零和x之间返回结果,这个问题萌生了(这甚至是英语吗?).
为我开启的ABS(CHECKSUM(NEWID())) % 5 + 1)是为每一行重新评估的简单观察.我的印象是ABS(CHECKSUM(NEWID())) % 5 + 1)会被评估一次,然后匹配.
谢谢大家回答,慢慢但肯定会让我更好地理解.
发生这种情况的原因是因为NEWID()为表中的每一行添加了不同的值.对于每一行,独立于其他行,有五分之一的机会被退回.因此,就目前情况而言,实际上您返回的所有5行的机率为1:3125!
要查看此内容,请运行以下查询.您会看到每一行都有不同的ID.
SELECT * , NEWID()
FROM @Table
Run Code Online (Sandbox Code Playgroud)
这将修复您的代码:
DECLARE @Id int
SET @Id = ABS(CHECKSUM(NEWID())) % 5 + 1
SELECT *
FROM @Table
WHERE ID = @Id
Run Code Online (Sandbox Code Playgroud)
但是,我不确定这是从表中选择单个随机行的最有效方法.
您可能会发现此MSDN文章很有用:http://msdn.microsoft.com/en-us/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
Run Code Online (Sandbox Code Playgroud)