我试图在单个查询中切换一个关系,如果该关系已经存在,它将删除该关系,否则它将创建它。我可以在第三列添加一个布尔值来切换它,但我宁愿删除它。
架构
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 ($1,$2) ON CONFLICT (profile_id,thead_id)
DO DELETE FROM thread_subscription
WHERE profile_id = $1 AND thread_id = $2;
答案 0 :(得分:1)
因此,您的意图是在表上运行INSERT
顺序,并且您希望在重复键上实际上会DELETE
相关记录。尽管在技术上可行,但我不建议您进行此设置,因为这是远距离操作,很难调试。
但是,使用Postgres函数可以实现相同类型的功能。这样一来,在涉及到切换订阅时,意图就变得很明确,并且不会干扰标准数据库语句(INSERT
)。
以下是该函数的代码:它接受两个参数作为输入,验证订阅表中是否已存在记录,然后执行相关操作;它在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;
答案 1 :(得分:1)
除了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小提琴链接。