簡體   English   中英

是否可以在 postgres 中捕獲已創建行的 ID 以在同一查詢中使用?

[英]Is it possible to capture the ID of a created row in postgres to use in the same query?

TL; DR,我想知道是否可以在 postgres 中創建一個資源,然后創建另一個引用它的資源,所有這些都在同一個語句中。 我想這樣做是為了減少往返時間並簡化我的后端邏輯。

我目前有兩個資源,foo 和 bar。 Bar 是引用它的 foo 的子資源:

CREATE TABLE foos (
    id serial PRIMARY KEY,
    name VARCHAR ( 50 ) UNIQUE NOT NULL
);

CREATE TABLE bars (
    id serial PRIMARY KEY,
    name VARCHAR ( 50 ) NOT NULL,
    description VARCHAR ( 50 ),
    foo_id int NOT NULL,
    FOREIGN KEY (foo_id)
      REFERENCES foos (id),
    UNIQUE (foo_id, name) 
);

我目前有以下 sql 語句在端點v1/foos/{foo_name}/bars/{bar_name}上插入 foo 和 bar:

WITH upsert_foo AS
    (
        INSERT INTO "foos" 
        ("name")
        VALUES 
        ($1)
        ON CONFLICT ("name") DO NOTHING
    ),
     upsert_bar AS
      (
         INSERT INTO "bars" 
         ("name", "description", "foo_id" )
         VALUES 
         ($2, $3,   
            (SELECT "id" FROM "foos" WHERE "name" = $1) )
        ON CONFLICT ("name", "foo_id") DO 
        UPDATE SET
                 "description" = EXCLUDED."description",
            RETURNING *
    )
    SELECT upsert_bar.*;

當用戶 upsert 一個 bar 時,如果它不存在,則應創建一個名稱來自 URI 的 foo,如果它不存在則應創建該 bar。 否則,應該更新欄。

但是,此語句僅適用於更新情況,即 foo 資源已經存在。 新創建的 foo 似乎沒有出現在(SELECT "id" FROM "foos" WHERE "name" = $1)中。

有沒有辦法可以捕獲已創建(或已存在)的 foo 的 ID 並在創建欄 object 時使用它?

我唯一能想到的就是將其分解為單獨的操作:

INSERT INTO 
   "foos" ("name")
VALUES 
    ($1)
ON CONFLICT ("name") DO UPDATE 
    SET name = foos.name
RETURNING id;

上面有一個丟棄的UPDATE用於捕獲id值。 將此值保存到變量中以用作下面的$4

然后:

INSERT INTO 
   "bars" ("name", "description", "foo_id" )
VALUES 
   ($2, $3, $4)
ON CONFLICT ("name", "foo_id") DO UPDATE 
    SET "description" = EXCLUDED."description"
RETURNING *

我設法在一個語句中完成了這項工作,但這有點復雜:

WITH insert_foo AS
(
    INSERT INTO "foos" 
    ("name")
    VALUES 
    ($1)
    ON CONFLICT ("name") DO NOTHING RETURNING *
),
upsert_foo AS
(
    SELECT * FROM insert_foo
    UNION
    SELECT * FROM foos WHERE "name"=$1
),
upsert_bar AS
  (
     INSERT INTO "bars" 
     ("name", "description", "foo_id" )
     VALUES 
     ($2, $3, (SELECT "id" FROM upsert_foo WHERE name=$1) )
    ON CONFLICT ("name", "foo_id") DO 
    UPDATE SET
             "description" = EXCLUDED."description"
    RETURNING *
)
SELECT * FROM upsert_bar;

基本上,插入的結果應該與常規的 select 查詢聯合,其中只有一個包含一行,具體取決於 foo 是否已經存在。 然后我可以 select 來自此聯合查詢結果的 id。

我想向 Adrian Klaver 大聲喊叫,因為他指出了我正確的方向以及這個答案: https://stackoverflow.com/a/62205017/4600258

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM