PostgreSQL嵌套CTE和UNION

32

我正在尝试学习SQL,使用的是PostgreSQL 9.1.3。我想要理解一些让我感到不一致的行为。举个例子:

这个可以正常工作:


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);也许解析器太挑剔或者太过敏感了。个人而言,我经常使用很多嵌套CTE(最多四层深度),但除了递归CTE之外,我很少使用UNION。 - wildplasser
2
@AdamMackler,你应该把那个作为你自己问题的答案。 - araqnid
4
Tom Lane承认你发现了一个错误,就像是他正式批准你提出了一个非常好的问题。请将你从列表中得到的内容作为答案发布,并确保添加一个指向该主题的链接。 - Erwin Brandstetter
1个回答

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

This is a bug :-(. The parse analysis code seems to think that WITH can only be attached to the top level or a leaf-level SELECT within a set operation tree; but the grammar follows the SQL standard which says no such thing. The WITH gets accepted, and attached to the intermediate-level UNION which is where syntactically it should go, and then it's entirely ignored during parse analysis. Will see about fixing it.

      regards, tom lane

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


6
似乎在9.2 beta3中已经解决了这个问题。我引用了新闻通讯中的一句话:* 修复了使用集合操作(UNION/INTERSECT/EXCEPT)时WITH语句的问题 - Erwin Brandstetter
5
我刚刚安装了9.2beta3,是的,我原帖中无法运行的命令现在可以按预期工作了。感谢你提供信息。 - Adam Mackler
2
太棒了!谢谢你追踪到这个问题!你的问题值得更多的赞。 :) 顺便说一句,在这种情况下,鼓励接受自己(正确的)答案。 - Erwin Brandstetter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接