我每次需要从表中获取10个随机行,但是当我重复查询时,行不会重复。
但是,如果我得到所有行,它将从一个重复,如表有20行,第一次我得到10个随机行,第二次我将需要剩余10行,在我的第3个查询我需要得到随机10行。
目前我的查询是随机获取10行:
SELECT TOP 10 *
FROM tablename
ORDER BY NEWID()
但是MSDN建议这个查询
SELECT TOp 10 * FROM Table1
WHERE (ABS(CAST(
(BINARY_CHECKSUM(*) *
RAND()) as int)) % 100) < 10
表现良好。但是这个查询不返回常量行。你能否就此提出一些建议
答案 0 :(得分:2)
由于第二个查询的必需结果取决于第一个查询的(随机)结果,因此查询不能是无状态查询。您需要以某种方式将状态(有关以前的查询/查询的信息)存储在某处。
最简单的解决方案可能是将已检索的行或其ID存储在临时表中,然后在第二个查询中查询... where id not in (select id from temp_table)
。
答案 1 :(得分:0)
正如Jiri Tousek所说,您运行的每个查询都必须知道先前的查询返回了什么。
我没有在表中插入先前返回的行的ID,而是检查新表中的新结果,而只是在表中添加一个列,其中随机数将定义一个新的随机顺序行。
您使用随机数填充此列一次。
这会记住行的随机顺序并使其保持稳定,因此您需要记住的是,您到目前为止所请求的随机行数是多少。然后从您在上一个查询中停止的位置开始,根据需要获取尽可能多的行。
向表中添加列RandomNumber binary(8)
。您可以选择不同的尺寸。 8个字节就足够了。
用随机数填充它。一次。
UPDATE tablename
SET RandomNumber = CRYPT_GEN_RANDOM(8)
在RandomNumber
列上创建索引。独特的指数。如果事实证明存在重复的随机数(对于20,000行和8字节长的随机数不太可能),则重新生成随机数(再次运行UPDATE
语句)直到所有这些都是唯一的。
请求前10个随机行:
SELECT TOP(10) *
FROM tablename
ORDER BY RandomNumber
在处理/使用这10个随机行时,请记住上次使用的随机数。最好的方法取决于你如何处理这10个随机行。
DECLARE @VarLastRandomNumber binary(8);
SET @VarLastRandomNumber = ...
-- the random number from the last row returned by the previous query
请求接下来的10个随机行:
SELECT TOP(10) *
FROM tablename
WHERE RandomNumber > @VarLastRandomNumber
ORDER BY RandomNumber
处理它们并记住最后使用的随机数。
重复。作为奖励,您可以在每次迭代时请求不同数量的随机行(每次不必为10)。
答案 2 :(得分:0)
我要做的是有两个新字段,SELECTED(int)和TimesSelected(整数)然后
UPDATE tablename SET SELECTED = 0;
WITH CTE AS (SELECT TOP 10 *
FROM tablename
ORDER BY TimesSelected ASC, NEWID())
UPDATE CTE SET SELECTED = 1, TimesSelected = TimesSelected + 1;
SELECT * from tablename WHERE SELECTED = 1;
所以如果你每次都使用它,一旦选中了一个记录就到了堆的顶部,并且它下面的记录是随机选择的。
你可能想在SELECTED上放一个索引并执行
UPDATE tablename SET SELECTED = 0 WHERE SELECTED = 1; -- for performance
答案 3 :(得分:0)
最优雅的解决方案,如果您在一定时间内完成连续查询,将使用游标:
DECLARE rnd_cursor CURSOR FOR
SELECT col1, col2, ...
FROM tablename
ORDER BY NEWID();
OPEN rnd_cursor;
FETCH NEXT FROM rnd_cursor; -- Repeat ten times
保持光标打开,只需在需要时继续提取行。完成后关闭光标:
CLOSE rnd_cursor;
DEALLOCATE rnd_cursor;
至于问题的第二部分,一旦你拿到最后一行,打开一个新光标:
IF @@FETCH_STATUS <> 0
BEGIN
CLOSE rnd_cursor;
OPEN rnd_cursor;
END;