在冲突中删除postgres

时间:2019-01-07 22:12:22

标签: sql postgresql

我试图在单个查询中切换一个关系,如果该关系已经存在,它将删除该关系,否则它将创建它。我可以在第三列添加一个布尔值来切换它,但我宁愿删除它。

架构

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;

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小提琴链接。