冲突时删除 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 DELETE1 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.