迭代 cte 中的随机值
Random values in iterative cte's
使用 SQL 服务器 2016+
我在从 table 中选择随机行时遇到了一些困难,这已缩小为随机数生成方式的问题。为了提高效率,使用 TOP 10 * ORDER BY NEWID()
会很慢。在下面的代码中,我为 repeatable 结果使用了一组种子,但在现场我不会。
代码示例:
SELECT RAND(100) RN
, RAND()
, RAND()
, RAND()
, RAND();
SELECT RAND(100) RN
UNION ALL SELECT RAND()
UNION ALL SELECT RAND()
UNION ALL SELECT RAND()
UNION ALL SELECT RAND();
WITH cte AS
(SELECT 1 ID
, RAND(100) RN
UNION ALL
SELECT cte.ID + 1
, RAND()
FROM cte
WHERE ID < 5)
SELECT RN
FROM cte;
结果集
RN
---------------------- ---------------------- ---------------------- ---------------------- ----------------------
0.715436657367485 0.28463380767982 0.0131039082850364 0.28769876521071 0.100505471175005
(1 row affected)
RN
----------------------
0.715436657367485
0.28463380767982
0.0131039082850364
0.28769876521071
0.100505471175005
(5 rows affected)
RN
----------------------
0.715436657367485
0.28463380767982
0.28463380767982
0.28463380767982
0.28463380767982
(5 rows affected)
正如您从结果中看到的那样,当我以内联方式或通过联合重复调用 RAND()
函数时,每次调用都会得到不同的结果。但是,如果我在迭代 cte 中调用该函数,那么我会重复获得相同的值。
此代码是显示问题的示例,而不是整个代码集。我创建这个纯粹是为了演示这个问题。我有一个基于 Checksum
& NewID()
和模数调用和乘法组合的解决方案,可以给我想要的范围内的值,但这相当复杂,而且对于仅生成列表来说似乎过多范围内的随机数。
我正在寻找可以在
上提供的任何指导
- 为什么会这样
- 任何解决问题的方法
- 生成随机数列表的其他选项(不是 RBAR)
非常感谢。
RAND()
returns 查询中的 "constant" 值。也就是说,它在查询中每 "mention" 计算一次。
你可以看到这个如果你 运行:
select rand(), rand()
from (values (1), (2), (3)) v(x);
每行有两个不同的值。但是,这些列具有相同的值。
无论如何,规范的答案是使用RAND(CHECKSUM(NEWID()))
。这为每次调用提供了 RAND()
的随机种子:
WITH cte AS
(SELECT 1 as ID, RAND(CHECKSUM(NEWID())) as RN
UNION ALL
SELECT cte.ID + 1, RAND(CHECKSUM(NEWID())) as RN
FROM cte
WHERE ID < 5
)
SELECT RN
FROM cte;
这可能足以获取随机值列表。我怀疑您的 real 问题是不同的——类似于从 table 中提取随机行。如果这是真正的问题,请提出 新 问题或检查类似问题。
使用 SQL 服务器 2016+
我在从 table 中选择随机行时遇到了一些困难,这已缩小为随机数生成方式的问题。为了提高效率,使用 TOP 10 * ORDER BY NEWID()
会很慢。在下面的代码中,我为 repeatable 结果使用了一组种子,但在现场我不会。
代码示例:
SELECT RAND(100) RN
, RAND()
, RAND()
, RAND()
, RAND();
SELECT RAND(100) RN
UNION ALL SELECT RAND()
UNION ALL SELECT RAND()
UNION ALL SELECT RAND()
UNION ALL SELECT RAND();
WITH cte AS
(SELECT 1 ID
, RAND(100) RN
UNION ALL
SELECT cte.ID + 1
, RAND()
FROM cte
WHERE ID < 5)
SELECT RN
FROM cte;
结果集
RN
---------------------- ---------------------- ---------------------- ---------------------- ----------------------
0.715436657367485 0.28463380767982 0.0131039082850364 0.28769876521071 0.100505471175005
(1 row affected)
RN
----------------------
0.715436657367485
0.28463380767982
0.0131039082850364
0.28769876521071
0.100505471175005
(5 rows affected)
RN
----------------------
0.715436657367485
0.28463380767982
0.28463380767982
0.28463380767982
0.28463380767982
(5 rows affected)
正如您从结果中看到的那样,当我以内联方式或通过联合重复调用 RAND()
函数时,每次调用都会得到不同的结果。但是,如果我在迭代 cte 中调用该函数,那么我会重复获得相同的值。
此代码是显示问题的示例,而不是整个代码集。我创建这个纯粹是为了演示这个问题。我有一个基于 Checksum
& NewID()
和模数调用和乘法组合的解决方案,可以给我想要的范围内的值,但这相当复杂,而且对于仅生成列表来说似乎过多范围内的随机数。
我正在寻找可以在
上提供的任何指导- 为什么会这样
- 任何解决问题的方法
- 生成随机数列表的其他选项(不是 RBAR)
非常感谢。
RAND()
returns 查询中的 "constant" 值。也就是说,它在查询中每 "mention" 计算一次。
你可以看到这个如果你 运行:
select rand(), rand()
from (values (1), (2), (3)) v(x);
每行有两个不同的值。但是,这些列具有相同的值。
无论如何,规范的答案是使用RAND(CHECKSUM(NEWID()))
。这为每次调用提供了 RAND()
的随机种子:
WITH cte AS
(SELECT 1 as ID, RAND(CHECKSUM(NEWID())) as RN
UNION ALL
SELECT cte.ID + 1, RAND(CHECKSUM(NEWID())) as RN
FROM cte
WHERE ID < 5
)
SELECT RN
FROM cte;
这可能足以获取随机值列表。我怀疑您的 real 问题是不同的——类似于从 table 中提取随机行。如果这是真正的问题,请提出 新 问题或检查类似问题。