公用表表达式 (CTE) 连接中的 RANDOM()
值的行为与 SQLite 中的预期不同。
SQL:
WITH
tbl1(n) AS (SELECT 1 UNION ALL SELECT 2),
tbl2(n, r) AS (SELECT n, RANDOM() FROM tbl1)
SELECT * FROM tbl2 t1 CROSS JOIN tbl2 t2;
示例 SQLite 结果:
n r n r
1 7058971975145008000 1 8874103142384122000
1 1383551786055205600 2 8456124381892735000
2 2646187515714600000 1 7558324128446983000
2 -1529979429149869800 2 7003770339419606000
每列中的随机数都是不同的。但是
CROSS JOIN
重复行 - 所以我希望每列中有 2 对相同的数字 - 这是 PostgreSQL , Oracle 11g 和 SQL Server 2014 的情况(使用基于行的种子时)。示例 PostgreSQL/Oracle 11g/SQL Server 2014 结果:
n r n r
1 0.117551110684872 1 0.117551110684872
1 0.117551110684872 2 0.221985165029764
2 0.221985165029764 1 0.117551110684872
2 0.221985165029764 2 0.221985165029764
问题
JOIN
中使用时将保持固定? 最佳答案
您的问题相当冗长且杂乱无章-没有一个问题。但是,这很有趣,我学到了一些东西。
这种说法是不正确的:
SQL Server assigns a random seed to the RAND() function: When used in a SELECT, it is only seeded once rather than for each row.
SQL Server 具有运行时常量函数的概念。这些是从已编译查询中提取并在查询开始时每个表达式执行一次的函数。最突出的例子是
getdate()
(以及相关的日期/时间函数)和 rand()
.如果你运行,你可以很容易地看到这一点:
select rand(), rand()
from (values (1), (2), (3)) v(x);
每列具有相同的值,但列之间的值不同。
大多数数据库——包括 SQLite——对
rand()
有更直观的解释。/random()
. (作为个人说明,在每一行上返回相同值的“随机”函数非常违反直觉。)每次调用它时,您都会得到不同的值。对于 SQL Server,您通常会使用 newid()
的表达式。 :select rand(), rand(), rand(checksum(newid()))
from (values (1), (2), (3)) v(x);
至于您的第二个问题,SQLite 似乎实现了递归 CTE。所以这就是你想要的:
WITH tbl1(n) AS (
SELECT 1 UNION ALL SELECT 2
),
tbl2(n, r) AS (
SELECT n, RANDOM()
FROM tbl1
union all
select *
from tbl2
where 1=0
)
SELECT *
FROM tbl2 t1 CROSS JOIN tbl2 t2;
我没有看到任何文件证明是这种情况,因此使用风险自负。 Here是一个 DB-Fiddle。
而且,作为记录,这似乎也适用于 SQL Server。我刚刚学到了一些东西!
编辑:
正如评论中所建议的,物化可能并不总是发生。它似乎确实适用于同一级别的两个引用:
WITH tbl1(n) AS (
SELECT 1 UNION ALL SELECT 2),
tbl2(n, r) AS (
SELECT n, RANDOM()
FROM tbl1
union all
select *
from tbl2
where 1=0
)
SELECT t2a.r, count(*)
FROM tbl2 t2a left JOIN
tbl2 t2b
on t2a.r = t2b.r
GROUP BY t2a.r;
关于sql - 为什么 SQLite CTE JOIN 中的 RANDOM() 行为与其他 RDBMS 不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50289527/