繁体   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