sql - 为什么 SQLite CTE JOIN 中的 RANDOM() 行为与其他 RDBMS 不同?

标签 sql sqlite random common-table-expression

公用表表达式 (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 对相同的数字 - 这是 PostgreSQLOracle 11gSQL 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

问题
  • 可以解释SQLite中的行为吗?它是一个错误吗?
  • 有没有办法让 CTE 中的表 B(基于同一 CTE 中的表 A)有一个额外的随机生成数字列,在 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/

    相关文章:

    mysql - MySQL 中的右连接

    mysql - 仅选择具有多个相同字段值的 4 条记录之一

    sql - 根据周差计算日期

    android - sqlite 中按月分组

    python - 如何将随机数分配给变量?

    php - 从平面文本文件中抓取一个随机项目 - php?

    python - 有没有更有效的方法在 Django 中根据条件参数数量编写此自定义 SQL?

    android - 如何在 SQLite 数据库中存储和检索字节数组(图像数据)?

    android - SQLite 对比纯文本(安卓/新手)

    java - 生成泊松和二项式随机数的算法?