3

テーブルfooがあります

                            Table "public.foo"
      Column       |            Type             |              Modifiers              
-------------------+-----------------------------+-------------------------------------
 foo_id            | uuid                        | not null default uuid_generate_v1()
 col1              | uuid                        | 
 col2              | uuid                        | 
 col3              | uuid                        | not null

主に foo から選択するビューgoo_viewがありますが、別のテーブルにも参加します

SELECT * from foo LEFT JOIN foo_helper USING (foo_id);

適切なgoo_view情報を返しながら、テーブルfooに挿入しようとしている次の CTE クエリがあります。

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 構文のようです。

私の最善の推測は、あなたが使用している戻り句が1つの foo_id を返しているということです。. . 挿入したばかりのもの。この foo_id はおそらく goo_view に存在しないため、一致するものはなく、空のセットです。

そして、あなたがやろうとしていることは、ドキュメントでは明示的に許可されていません:

WITH のサブステートメントは、相互に、およびメイン クエリと同時に実行されます。したがって、WITH でデータ変更ステートメントを使用する場合、指定された更新が実際に発生する順序は予測できません。すべてのステートメントは同じスナップショットで実行されるため (第 13 章を参照)、ターゲット テーブルに対する互いの影響を「見る」ことはできません。これにより、行更新の実際の順序が予測できないという影響が緩和され、異なる WITH サブステートメントとメイン クエリの間で変更をやり取りする唯一の方法は RETURNING データになります。. .

そのため、ビューに新しい行は表示されません。fromこれを修正するには、 によって返された結果を使用して、句でCTE を明示的に参照する必要がありますreturning

于 2012-12-26T19:48:38.140 に答える
1

ところで:分離レベルに関しては、CTE、連鎖されたRETURNING、サブクエリ、またはプレーン結合の間に違いはありません(あるべきです)。「後続の」サブクエリが実際のテーブルのタプルを参照する (つまり、選択を行う) 場合、クエリの開始時点での行を「参照」する必要があります。

それ以外の場合、以下の自己結合更新レイクを使用したクエリは機能しませんでした:

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 に答える
1

ビューは 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);

このようにして、新しく挿入された値を取得し、それにセカンダリ テーブルを結合します。

于 2012-12-26T20:10:50.627 に答える