CTE中插入的行不能在postgreSQL中加入?

CTE中插入的行不能在postgreSQL中加入?,sql,postgresql,postgresql-9.1,Sql,Postgresql,Postgresql 9.1,我有一张桌子 Table "public.foo" Column | Type | Modifiers -------------------+-----------------------------+------------------------------------- foo_id |

我有一张桌子

                            Table "public.foo"
      Column       |            Type             |              Modifiers              
-------------------+-----------------------------+-------------------------------------
 foo_id            | uuid                        | not null default uuid_generate_v1()
 col1              | uuid                        | 
 col2              | uuid                        | 
 col3              | uuid                        | not null
我有一个视图goo_view,它主要从foo中选择,但也加入另一个表

SELECT * from foo LEFT JOIN foo_helper USING (foo_id);
我在下面的CTE查询中尝试插入表foo,同时返回相应的goo\u视图信息

WITH ins AS (
    INSERT INTO foo (col1,col2, col3) VALUES (111,222,333) RETURNING foo_id
)                              
SELECT v.foo_id, v.col1, v.col2, v.fk1
FROM goo_view v 
JOIN ins 
USING (foo_id)   
但是结果是空的

如果我分别运行insert和select,它会工作,是不是因为时间安排的原因而失败了


解决方法是什么?

为什么要在CTE中使用insert

WITH ins AS (
    select 111 as col1, 222 as col2, 333 as col3
) 
. . .
你的语法真的有用吗?我以前没见过。哇,我刚刚学到了一些东西。这似乎是错误的

我最好的猜测是,您使用的returning子句返回一个foo_id。你刚才插入的那个。这个foo_id可能不存在于goo_视图中,因此没有匹配项和空集

而且,文档中不允许明确说明您要做的事情:

与中的子语句同时执行 和主查询。因此,在使用数据修改时 语句,指定的实际更新顺序 事情的发生是不可预测的。所有语句都以相同的方式执行 快照(见第13章),因此他们无法“看到”彼此的效果 在目标表上。这减轻了压力的影响 行更新的实际顺序不可预测,这意味着 返回数据是在用户之间传递更改的唯一方法 与子语句和主查询不同


因此,您不会在视图中看到新行。要解决此问题,您必须在
from
子句中显式引用CTE,使用
returning

返回的结果,因为视图在SQL命令开始的状态下从表
foo
中进行选择,所以您必须重写如下内容:

WITH ins AS (
   INSERT INTO foo (col1,col2, col3) VALUES (111,222,333)
   RETURNING foo_id, col1, col2
   )
SELECT i.foo_id, i.col1, i.col2, h.fk1
FROM   ins i
LEFT   JOIN foo_helper h USING (foo_id);

通过这种方式,您可以获取新插入的值并将辅助表连接到该表。

顺便说一句:关于隔离级别,CTE、链式返回、子查询或普通连接之间(应该)没有区别。如果“后续”子查询引用实际的表元组(即执行select),那么它应该在查询开始时“看到”行

在其他情况下,具有以下自连接更新湖的查询无法工作:

SET search_PATH='tmp';

DROP TABLE ztable CASCADE;
CREATE TABLE ztable
    ( id integer NOT NULL PRIMARY KEY
    , payload varchar
    );
INSERT INTO ztable(id,payload) VALUES (1,'one' ), (2,'two' ), (3,'three')
      ,(4,'four' ), (5,'five' ), (6,'six' );
SELECT * FROM ztable;

    -- This can only work if 
    -- t2 is seen in its original form
    -- **before the update**
UPDATE ztable t1
SET payload=t2.payload
FROM ztable t2
WHERE t1.id  = 7-t2.id
    ;
SELECT * FROM ztable;
结果:

CREATE TABLE
INSERT 0 6
 id | payload 
----+---------
  1 | one
  2 | two
  3 | three
  4 | four
  5 | five
  6 | six
(6 rows)

UPDATE 6
 id | payload 
----+---------
  6 | one
  5 | two
  4 | three
  3 | four
  2 | five
  1 | six
(6 rows)

CTE返回的元组或返回的“链表表达式”当然是虚拟的;它们不是指实际的元组,而是指新“合成”的新实体。

很明显,由于我得到了一个emtpy结果,所以出现了一些问题,但它不会触发语法错误。。我正在寻找一种从insert语句中获得更好返回结果的方法。我希望返回的类型包括视图中的字段以及表中的字段本身。我使用类似的语法来捕获插入后的“新鲜”序列,但我在另一个表中使用它们,例如将它们插入临时“中心”表。在我看来,视图不应该看到在语句begin之前插入或更新的行。非常遗憾,我真的希望能够在此处维护我的视图而不是我的语句…您也可以使用左联接将新行调用到视图中;-)或者一个右连接。(他们对伟人的评价…@DavidChan:然后你必须将操作分成两个SQL命令,最好是在一个事务中。如果已知插入值的组合是唯一的,则可以将这些值用作视图的
WHERE
条件。或者,您可以将
RETURNING
子句的结果保存在临时表中。或者您可以编写一个plpgsql函数,将整个操作自动封装到单个事务中。。。