【问题标题】:On conflict delete postgres冲突删除 postgres
【发布时间】:2019-01-07 22:12:22
【问题描述】:

我试图在单个查询中切换一个关系,如果它已经存在,它会删除该关系,否则它会创建它。我可以添加带有 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 ($1,$2) ON CONFLICT (profile_id,thead_id) 
DO DELETE FROM thread_subscription 
WHERE profile_id = $1 AND thread_id = $2;

【问题讨论】:

  • 当您尝试插入的profile_id,thread_id 已经存在于表中时,您想做什么?不是DELETE 我想象的那样?
  • 是的,我想删除它(只是关系而不是实际的配置文件或线程)。此查询位于 api 端点后面,用于将用户个人资料的订阅状态切换到论坛线程。
  • 所以你对一个表运行INSERT,并且你期望在某些情况下它实际上会执行DELETE?这看起来不是一个好方法。如果你想INSERT,那么INSERT。如果你想DELETE,那么DELETE。但必须在应用程序中做出选择,然后再运行查询
  • 我想在单个查询中切换关系。我不认为这是一个晦涩难懂的操作。

标签: sql postgresql stored-procedures sql-insert sql-delete


【解决方案1】:

所以您的意图是在表上运行INSERT 订单,并且您希望在重复键上它实际上将DELETE 相关记录。虽然技术上可行,但我不推荐这种设置,因为这是远距离操作,很难调试。

但是,可以使用 Postgres 函数实现相同类型的功能。这使得在切换订阅时意图明确,并且不会干扰标准数据库语句 (INSERT)。

这里是函数的代码:它接受两个参数作为输入,验证订阅表中是否已经存在记录,然后执行相关操作;它在DELETE 上返回0,在INSERT 上返回1。您可以查看 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;

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2017-12-06
      • 2017-03-13
      • 1970-01-01
      • 1970-01-01
      • 2017-04-03
      • 2019-08-15
      • 2011-11-12
      • 2012-03-27
      • 1970-01-01
      相关资源
      最近更新 更多