3

我有一张桌子

                            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_view信息

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)   

但是结果是空的。

如果我运行插入并单独选择它可以工作,是否存在导致此失败的时间?

解决方法是什么?

4

3 回答 3

3

为什么在 CTE 中使用插入物?

WITH ins AS (
    select 111 as col1, 222 as col2, 333 as col3
) 
. . .

你的语法真的有用吗?我以前没见过。哇,我刚刚学到了一些东西。这似乎是Postgres 语法

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

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

WITH 中的子语句彼此同时执行,并与主查询同时执行。因此,当在 WITH 中使用数据修改语句时,指定更新实际发生的顺序是不可预测的。所有语句都使用同一个快照执行(参见第 13 章),因此它们无法“看到”彼此对目标表的影响。这减轻了行更新的实际顺序的不可预测性的影响,并且意味着返回数据是在不同的 WITH 子语句和主查询之间传达更改的唯一方法。. .

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

于 2012-12-26T19:48:38.140 回答
1

由于视图foo在 SQL 命令开始的状态下从表中进行选择,因此您必须重写为:

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);

通过这种方式,您可以获取新插入的值并将辅助表加入其中。

于 2012-12-26T20:10:50.627 回答
1

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

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

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 返回的元组或 RETURNING 产生的“链表表达式”当然是虚拟的;它们不是指实际的元组,而是指新“合成”的新实体。

于 2012-12-26T20:31:32.720 回答