以下使用非确定性函数的查询会产生两个相同的行 - CTE 被计算并重新使用。
WITH foo AS (SELECT uuid_generate_v4() AS id)
SELECT id FROM foo
UNION ALL
SELECT id FROM foo
| id
| 741f4f69-416b-4b4c-9226-559527f4a84e
| 741f4f69-416b-4b4c-9226-559527f4a84e
这个执行有保证吗?postgres 可以决定将它内联到
SELECT id FROM (SELECT uuid_generate_v4() AS id) t
UNION ALL
SELECT id FROM (SELECT uuid_generate_v4() AS id) t
| id
| 262f0006-b4d5-440a-a86a-d79cd2684458
| c24b5835-9c5c-4d6f-b649-8e510129015b
这会产生两个不同的 ID(因此会产生不同的结果)?
SQL 标准规定了什么?Postgres 是否提供任何额外的保证?如果不能保证,重用依赖于非确定性过程的语句的标准方法是什么?
是的,这次执行有保证。Postgres 不会以您提到的方式内联它。
SQL 标准没有定义这种情况下的行为,而是将其留给了 SQL 服务器的实现。它(无论如何都是 2013 年草案)特别是在第7.6 节 <table reference>中说
其中 <query name> 是由
WITH
子句定义的,而在4.22 Determinism中它提到:第4.15.8 节派生表和游标的语法分析可以解释为意味着
uuid_generate_v4()
在您的案例中对的每个引用都会在语法树上产生一个不同的节点。特定 DBMS 的优化器是否选择尊重其非确定性性质并执行该函数两次是特定于实现的。