PostgreSQL 嵌套 CTE 和 UNION

Posted

技术标签:

【中文标题】PostgreSQL 嵌套 CTE 和 UNION【英文标题】:PostgreSQL nested CTE and UNION 【发布时间】:2012-07-29 06:54:30 【问题描述】:

我正在尝试使用 PostgreSQL 9.1.3 学习 SQL。我想了解一些让我觉得不一致的行为。也就是说:

这行得通:

WITH innermost AS (SELECT 2)
SELECT * FROM innermost
UNION SELECT 3;

我明白了:

 ?column? 
----------
        2
        3

这行得通:

WITH outmost AS (
        (WITH innermost AS (SELECT 2)
         SELECT * FROM innermost)
)                                
SELECT * FROM outmost;

结果:

?column? 
----------
        2

这也有效:

WITH outmost AS (
  SELECT 1
  UNION (WITH innermost AS (SELECT 2)
         SELECT * FROM innermost)
)
SELECT * FROM outmost;

我明白了:

 ?column? 
----------
        1
        2

但这确实不起作用

WITH outmost AS (
  SELECT 1
  UNION (WITH innermost as (SELECT 2)
         SELECT * FROM innermost
         UNION SELECT 3)
)
SELECT * FROM outmost;

结果:

ERROR:  relation "innermost" does not exist
LINE 4:          SELECT * FROM innermost

以我的思维方式,要么最后一个应该成功,要么其他一个应该失败。我没有看到模式。是否有一些通用规则可以让我预测嵌套 CTE 和 UNION 的哪些组合将起作用或不起作用?

【问题讨论】:

虽然您的最终查询看起来很尴尬,但应该没问题,恕我直言。这可能是解析器中的优先级/关联性错误。有一些语义限制(无嵌套递归 CTE,IIRC);也许解析器太挑剔了,或者太容易触发了。就个人而言,我使用了很多嵌套的 CTE(最多 4 层深),但我很少使用 UNION,除了在递归 CTE 中。 @AdamMackler 你应该把它作为你自己问题的答案 Tom Lane 承认您发现了一个错误,就像官方批准您提出了一个非常好的问题。请将您从列表中获得的内容发布为答案,并确保添加该主题的链接。 【参考方案1】:

谜团解开了:我观察到的行为是一个已知的错误。我将相同的原始帖子发送到特定于 PostgreSQL 的列表并得到了这个答案:

这是一个错误:-(。解析分析代码似乎认为 WITH 只能附加到顶层或叶级 SELECT 内 设置操作树;但语法遵循 SQL 标准 说没有这样的话。 WITH 被接受,并附加到 中级 UNION 语法上应该去的地方, 然后在解析分析期间完全忽略它。会看到 修复它。

      regards, tom lane

http://archives.postgresql.org/pgsql-novice/2012-07/msg00113.php

【讨论】:

似乎这已在 9.2 beta3 中修复。我引用时事通讯:* Fix WITH issue with set operations (UNION/INTERSECT/EXCEPT). 我刚刚安装了 9.2beta3,是的,我原来帖子中的非工作命令现在可以按预期工作。感谢您的提醒。 酷!感谢您跟踪此事!你的问题值得更多的赞成。 :) 顺便说一句,在这种情况下,我们鼓励您接受您自己的(正确)答案。

以上是关于PostgreSQL 嵌套 CTE 和 UNION的主要内容,如果未能解决你的问题,请参考以下文章

如何在 postgres 中对相同的 CTE 表达式执行 UNION ALL?

PostgreSQL CTE 的一般并行性

将 PostgreSQL 递归 CTE 转换为 SQL Server

优化sql嵌套查询,使用CTE语法

PostgreSQL递归查询示例

PostgreSQL:让 STRING_AGG 尊重 CTE 的排序