遵循(简化)代码片段的目的是返回一个随机行。 不幸的是,当我们在查询分析器中运行此片段时,它返回0到3之间的结果。
由于我们的输入表恰好包含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)
会被评估一次,然后匹配。
谢谢大家回答,慢慢但肯定会让我更好地理解。
答案 0 :(得分:8)
发生这种情况的原因是因为NEWID()为表中的每一行添加了不同的值。对于每一行,独立于其他行,有五分之一的机会被退回。因此,就目前情况而言,实际上你返回的所有5行中都有1到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/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
答案 1 :(得分:2)
有点猜测,并且不确定SQL是否以这种方式工作,但是SQL不会为表中的每一行评估“ABS(CHECKSUM(NEWID()))%5 + 1”?如果是,那么每个评估可能会也可能不会返回当前行的ID值。
尝试这样做 - 首先显式生成随机数,然后匹配该单个值:
declare @targetRandom int
set @targetRandom = ABS(CHECKSUM(NEWID())) % 5 + 1
select * from @table where ID = @targetRandom
答案 2 :(得分:1)
请尝试以下操作,以便了解会发生什么:
SELECT ABS(CHECKSUM(NEWID())) % 5 + 1 AS Number, @Table.*
FROM @Table
WHERE ID = Number
答案 3 :(得分:1)
或者您可以使用RAND()而不是NEWID(),它只在MS SQL中的每个查询中评估一次
如果要使用CHECKSUM获取随机行,可以使用此方法。
SELECT TOP 1 *
FROM @Table
ORDER BY CHECKSUM(NEWID())
怎么样?
SELECT t.ID
, FK1 = (SELECT TOP 1 FK1 FROM @Table ORDER BY NEWID())
FROM @Table t
答案 4 :(得分:1)
这可以帮助您了解原因。 多次运行查询。 MY_FILTER = ID多少次?
SELECT *, ABS(CHECKSUM(NEWID())) % 5 + 1 AS MY_FILTER
FROM @Table
SELECT *, ABS(CHECKSUM(NEWID())) % 5 + 1 AS MY_FILTER
FROM @Table
SELECT *, ABS(CHECKSUM(NEWID())) % 5 + 1 AS MY_FILTER
FROM @Table
答案 5 :(得分:0)
我不知道这会对你有多大帮助,但试试这个..我明白你每次执行查询时都想要一个随机行..
select top 1 newid() as row,ID from @Table order by row
这是逻辑。每次执行查询时,都会为每一行分配一个newid,并且所有都是唯一的,您只需使用新生成的唯一生成的rowid对它们进行排序。然后你需要做的就是选择最顶层或任何你想要的东西..