gpt4 book ai didi

sql - 插入冲突时回滚触发器

转载 作者:行者123 更新时间:2023-11-29 11:36:52 25 4
gpt4 key购买 nike

我有这个:

CREATE FUNCTION upsert_user(u_name text, u_fullname text, u_email text, u_suffix text) RETURNS integer
LANGUAGE plpgsql
AS $$
DECLARE
userid users.id_user%TYPE;
BEGIN
LOOP
-- first try to update
UPDATE users SET "fullname" = u_fullname, "email" = u_email, "suffix" = u_suffix WHERE "name" = u_name RETURNING "id_user" INTO userid;
-- check if the row is found
IF FOUND THEN
RETURN userid;
END IF;
-- not found so insert the row
BEGIN
INSERT INTO users ("name", "fullname", "email", "suffix") VALUES (u_name, u_fullname, u_email, u_suffix) RETURNING "id_user" INTO userid;
RETURN userid;
EXCEPTION WHEN unique_violation THEN
-- do nothing and loop
END;
END LOOP;
END;
$$;

CREATE TRIGGER link_entity
BEFORE INSERT
ON public.users
FOR EACH ROW
EXECUTE PROCEDURE public.link_entity();

CREATE FUNCTION link_entity() RETURNS trigger
LANGUAGE plpgsql
AS $$ DECLARE
entityid integer;
BEGIN
INSERT INTO privileges_entities (name) VALUES (NEW.name) RETURNING privileges_entities.id_entity INTO entityid;
IF NOT FOUND THEN
RETURN NULL;
END IF;
NEW.ref_entity := entityid;
RETURN NEW;
END;
$$;

将 postgresql 更新到版本 9.5 后,我修改了函数 upsert_user 以在冲突时使用新指令:

CREATE FUNCTION upsert_user(u_name text, u_fullname text, u_email text, u_suffix text) RETURNS integer
LANGUAGE sql
AS $$
INSERT INTO users (name, fullname, email, suffix)
VALUES (u_name, u_fullname, u_email, u_suffix)
ON CONFLICT (name) DO UPDATE SET name=EXCLUDED.name, fullname=EXCLUDED.fullname, email=EXCLUDED.email, suffix=EXCLUDED.suffix
RETURNING id_user;
$$;

问题是,现在,即使插入用户表失败,新行也会插入到 privileges_entities 表中。如果用户插入导致冲突,是否可以回滚触发器?

最佳答案

这确实是使用新的 ON CONFLICT 子句的副作用。

我的解决方案是在 link_entity() 函数本身中添加一个检查,如果用户已经存在则阻止它继续。像这样:

CREATE FUNCTION link_entity() RETURNS trigger
LANGUAGE plpgsql
AS $$ DECLARE
entityid integer;
nameExists boolean;
BEGIN
EXECUTE format('SELECT EXISTS(SELECT 1 FROM %I.%I WHERE name = NEW.name)', TG_TABLE_SCHEMA, TG_TABLE_NAME) INTO nameExists;
IF nameExists THEN
RETURN NEW; -- just return, entity already linked
END IF;

INSERT INTO privileges_entities (name) VALUES (NEW.name) RETURNING privileges_entities.id_entity INTO entityid;
IF NOT FOUND THEN
RETURN NULL;
END IF;
NEW.ref_entity := entityid;
RETURN NEW;
END;
$$;

关于sql - 插入冲突时回滚触发器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35178114/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com