【问题标题】:How to conditionally UPDATE/INSERT after DELETE that doesn't find rows?如何在没有找到行的删除后有条件地更新/插入?
【发布时间】:2021-11-28 17:29:59
【问题描述】:

我正在尝试在删除不同表中的值后更新表。

这是我对这个问题的简化函数查询:

create function updateoutfit(_id uuid, _title text DEFAULT NULL::text, _garments json)
    returns TABLE(id uuid, title text, garments json)
    language sql
as
$$
WITH del AS (DELETE FROM outfit_garment WHERE outfit_garment.outfit_id = _id RETURNING outfit_id),
     updateOutfit AS (
       UPDATE outfit SET
         title = _title
         FROM del
         WHERE outfit.id = _id
         RETURNING id, title
     ),
     saveOutfitGarment as (
       insert into outfit_garment (position_x, outfit_id)
         SELECT "positionX",
         (SELECT updateOutfit.id from updateOutfit)
         from json_to_recordset(_garments) as x("positionX" float,
                                                outfit_id uuid) RETURNING json_build_object('positionX', position_x) as garments)
SELECT id,
       title,
       json_agg(garments)
from updateOutfit as outfit,
     saveOutfitGarment as garments
group by id, title;
$$;

如果有delete返回的outfit_id就好了:

DELETE FROM outfit_garment WHERE outfit_garment.outfit_id = _id RETURNING outfit_id

但如果没有要删除的行则失败。我尝试过这样的事情:

DELETE FROM outfit_garment WHERE outfit_garment.outfit_id = '1234' RETURNING (SELECT '1234' as outfit_id );

但它仍然返回 0 行。

有没有办法解决这个问题或更好的方法?

我正在使用 Postgres 13.2

【问题讨论】:

  • 当然看起来del 是一个uuid,但您的UPDATE outfit 指的是FROM del,这让我感到困惑。但我对 Postgres 还不流利。无论如何,是否可以使用if exists(... 包装所有内容并以不同方式处理?
  • 您为_garments 中的每个"positionX" 传递一个outfit_id UUID。但是然后你把它们扔掉并使用你传递给函数的_id uuid 代替(在通过 CTE updateOutfit 中的UPDATE 传递它之后。这是预期的吗?如果条件是,查询中的“条件”是什么不是第一个DELETE找到一行?

标签: sql json postgresql common-table-expression


【解决方案1】:

如果DELETE 没有找到符合条件的行,则其RETURNING 子句返回no rows

标题要求“在删除后有条件地更新/插入”,但正文抱怨它“如果没有要删除的行则失败”。如果存在要删除的行不是条件,那么条件是什么?

四肢走动,这可能就是你想要的:

CREATE FUNCTION updateoutfit(_id UUID, _title text DEFAULT NULL::text, _garments json)
  RETURNS TABLE (id UUID, title text, garments json)
  LANGUAGE sql AS
$func$
DELETE FROM outfit_garment WHERE outfit_id = _id;  -- DELETE if exists

INSERT INTO outfit (id, title)  -- UPSERT outfit
VALUES (_id, _title)
ON CONFLICT (id) DO UPDATE
SET    title = EXCLUDED.title;
   
WITH ins AS (  -- INSERT new rows in outfit_garment
   INSERT INTO outfit_garment (position_x, outfit_id)
   SELECT "positionX", _id
   FROM   json_to_recordset(_garments) AS x("positionX" float)  -- outfit_id UUID was unused!
   RETURNING json_build_object('positionX', position_x) AS garments
   )
SELECT _id, _title, json_agg(garments)
FROM   ins
GROUP  BY id, title;
$func$;

它从表 outfit_garment 中删除给定 UUID 的所有行,然后在表 outfit 中插入或更新一行,最后在表 outfit_garment 中添加新的详细行。任何传入_garmentsoutfit_id 都会被忽略。
然后它返回一行,其中所有服装合并为一个 JSON 值。

【讨论】:

  • 非常感谢您的帮助!我设法让查询工作!我在答案字段中发布了最终查询。再次感谢您!
【解决方案2】:

感谢您的询问@Erwin Brandstetter 我解决了我的问题。

这是我的最终查询:

create function updateoutfit(_id uuid, _garments json, _title text DEFAULT NULL::text)
    returns TABLE
            (
                id       uuid,
                title    text,
                garments json
            )
    language sql
as
$$
DELETE
FROM outfit_garment
WHERE outfit_id = _id;
WITH upd as (
    UPDATE outfit
        SET title = _title
        WHERE outfit.id = _id
        RETURNING id, title
),

     ins AS (
         insert into outfit_garment (position_x, garment_id, outfit_id)
             SELECT "positionX",
                    "id",
                    _id
             from json_to_recordset(_garments) as x("positionX" float,
                                                    "id" uuid
                 ) RETURNING json_build_object('positionX', position_x,
                                               'garmentId',
                                               garment_id
                 ) as garments
     )
SELECT id,
       title,
       json_agg(garments)
from upd,
     ins
group by id, title;
$$;

【讨论】:

  • 这还是有问题的:如果 CTE upd 中的 UPDATE 没有找到行,该函数将返回 no row,即使CTE ins 中的 INSERT 已插入行。可能有一个 FK 约束来防止这种情况并引发错误,但是在外部 SELECT 中包含 upd 是没有意义的。那么你宁愿有一个单独的UPDATE(或者像我的回答一样的UPSERT)。
  • 是的,在这种情况下,UPSERT 会更安全!
猜你喜欢
  • 2012-07-02
  • 2020-07-26
  • 2016-08-16
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多