冲突时删除 postgres
On conflict delete postgres
我正在尝试在单个查询中切换一个关系,如果它已经存在,它会删除该关系,否则会创建它。我可以添加带有 bool 的第三列来切换它,但我宁愿删除它。
架构
CREATE TABLE IF NOT EXISTS thread_subscription (
profile_id INTEGER REFERENCES profile (id),
thread_id INTEGER REFERENCES thread (id),
UNIQUE(profile_id,thread_id)
)
查询
INSERT INTO thread_subscription (profile_id,thread_id)
VALUES (,) ON CONFLICT (profile_id,thead_id)
DO DELETE FROM thread_subscription
WHERE profile_id = AND thread_id = ;
因此您的意图是 运行 table 上的 INSERT
订单,并且您希望在重复键上它实际上 DELETE
相关记录。虽然在技术上可行,但我不推荐这种设置,因为这是 远距离操作,很难调试。
但是可以使用 Postgres 函数实现相同类型的功能。这使得 切换 订阅的意图明确,并且不会干扰标准数据库语句 (INSERT
)。
函数代码如下:输入两个参数,验证订阅table中是否已有记录,然后执行相关操作;它 returns 0
DELETE
和 1
INSERT
。您可以查看 this db fiddle 以了解其工作原理的完整演示。
CREATE OR REPLACE FUNCTION toggle_subscription(
pid NUMERIC,
tid NUMERIC
)
RETURNS NUMERIC AS $$
DECLARE
row_exists NUMERIC;
BEGIN
SELECT 1
INTO row_exists
FROM thread_subscription
WHERE profile_id = pid and thread_id = tid;
IF (row_exists > 0) THEN
DELETE FROM thread_subscription WHERE profile_id = pid and thread_id = tid;
RETURN 0;
ELSE
INSERT INTO thread_subscription(profile_id, thread_id) VALUES(pid, tid);
RETURN 1;
END IF;
END;
$$
LANGUAGE plpgsql;
除了 GMB 的响应之外,您可以通过使用 PERFORM 而不是使用 SELECT 来避免使用变量。
CREATE OR REPLACE FUNCTION toggle_subscription(
pid NUMERIC,
tid NUMERIC
)
RETURNS NUMERIC AS $$
BEGIN
perform FROM thread_subscription WHERE profile_id = pid and thread_id = tid;
IF NOT FOUND THEN
INSERT INTO thread_subscription(profile_id, thread_id) VALUES(pid, tid);
RETURN 1;
ELSE
DELETE FROM thread_subscription WHERE profile_id = pid and thread_id = tid;
RETURN 0;
END IF;
END;
$$
LANGUAGE plpgsql;
this is fiddle link.
我正在尝试在单个查询中切换一个关系,如果它已经存在,它会删除该关系,否则会创建它。我可以添加带有 bool 的第三列来切换它,但我宁愿删除它。
架构
CREATE TABLE IF NOT EXISTS thread_subscription (
profile_id INTEGER REFERENCES profile (id),
thread_id INTEGER REFERENCES thread (id),
UNIQUE(profile_id,thread_id)
)
查询
INSERT INTO thread_subscription (profile_id,thread_id)
VALUES (,) ON CONFLICT (profile_id,thead_id)
DO DELETE FROM thread_subscription
WHERE profile_id = AND thread_id = ;
因此您的意图是 运行 table 上的 INSERT
订单,并且您希望在重复键上它实际上 DELETE
相关记录。虽然在技术上可行,但我不推荐这种设置,因为这是 远距离操作,很难调试。
但是可以使用 Postgres 函数实现相同类型的功能。这使得 切换 订阅的意图明确,并且不会干扰标准数据库语句 (INSERT
)。
函数代码如下:输入两个参数,验证订阅table中是否已有记录,然后执行相关操作;它 returns 0
DELETE
和 1
INSERT
。您可以查看 this db fiddle 以了解其工作原理的完整演示。
CREATE OR REPLACE FUNCTION toggle_subscription(
pid NUMERIC,
tid NUMERIC
)
RETURNS NUMERIC AS $$
DECLARE
row_exists NUMERIC;
BEGIN
SELECT 1
INTO row_exists
FROM thread_subscription
WHERE profile_id = pid and thread_id = tid;
IF (row_exists > 0) THEN
DELETE FROM thread_subscription WHERE profile_id = pid and thread_id = tid;
RETURN 0;
ELSE
INSERT INTO thread_subscription(profile_id, thread_id) VALUES(pid, tid);
RETURN 1;
END IF;
END;
$$
LANGUAGE plpgsql;
除了 GMB 的响应之外,您可以通过使用 PERFORM 而不是使用 SELECT 来避免使用变量。
CREATE OR REPLACE FUNCTION toggle_subscription(
pid NUMERIC,
tid NUMERIC
)
RETURNS NUMERIC AS $$
BEGIN
perform FROM thread_subscription WHERE profile_id = pid and thread_id = tid;
IF NOT FOUND THEN
INSERT INTO thread_subscription(profile_id, thread_id) VALUES(pid, tid);
RETURN 1;
ELSE
DELETE FROM thread_subscription WHERE profile_id = pid and thread_id = tid;
RETURN 0;
END IF;
END;
$$
LANGUAGE plpgsql;
this is fiddle link.