Postgresql批插入或忽略

Postgresql批插入或忽略,sql,postgresql,plpgsql,postgresql-9.1,duplicate-removal,Sql,Postgresql,Plpgsql,Postgresql 9.1,Duplicate Removal,我有责任将我们的代码从sqlite切换到postgres。下面是我遇到的一个问题 INSERT INTO group_phones(group_id, phone_name) SELECT g.id, p.name FROM phones AS p, groups as g WHERE g.id IN ($add_groups) AND p.name IN ($phones); 当存在重复记录时,会出现问题。在此表中,两个值的组合必须是唯一的。我在其他地方使用了一些plpgsql函数来执行更

我有责任将我们的代码从sqlite切换到postgres。下面是我遇到的一个问题

INSERT INTO group_phones(group_id, phone_name)
SELECT g.id, p.name 
FROM phones AS p, groups as g
WHERE g.id IN ($add_groups) AND p.name IN ($phones);
当存在重复记录时,会出现问题。在此表中,两个值的组合必须是唯一的。我在其他地方使用了一些plpgsql函数来执行更新或插入操作,但在这种情况下,我可以一次执行多个插入。我不知道如何为此编写存储例程。感谢所有sql专家的帮助

尝试以下操作:

INSERT INTO group_phones(group_id, phone_name)
SELECT DISTINCT g.id, p.name 
FROM phones AS p, groups as g
WHERE 
    g.id IN ($add_groups) 
    AND p.name IN ($phones)
    AND (g.id, p.name) NOT IN (
        SELECT group_id, phone_name
        FROM group_phones
    )
;
使用
DISTINCT
可以确保插入唯一的行,使用
NOT IN
子句可以排除已有的行


注意虽然此解决方案可能更容易理解,但在大多数情况下,欧文的表现会更好。

存在3个挑战

  • 您的查询在表
    电话
    之间没有
    连接
    条件
    ,这实际上是一个有限的
    交叉连接
    ——您可能并不打算这样做。也就是说,每一部合格的手机都与每一组合格的手机组合在一起。如果你有100部手机和100个通话组,那么已经有10000个组合了

  • 插入不同的
    组合(组id、电话号码)

  • 避免在表
    group\u phones
    中插入已经存在的行

  • 所有考虑因素都可能是这样的:

    INSERT INTO group_phones(group_id, phone_name)
    SELECT i.id, i.name
    FROM  (
        SELECT DISTINCT g.id, p.name -- get distinct combinations
        FROM   phones p
        JOIN   groups g ON ??how are p & g connected??
        WHERE  g.id IN ($add_groups)
        AND    p.name IN ($phones)
        ) i
    LEFT   JOIN group_phones gp ON (gp.group_id, gp.phone_name) = (i.id, i.name)
    WHERE  gp.group_id IS NULL  -- avoid duping existing rows
    
    如果事务回滚时出现序列化错误,请准备好重复该事务。 关于这个话题的更多信息,好的起点可以是这个或这个

    不过,通常情况下,你甚至不必为此费心

    演出 通常是最快的方法,右表中有不同的列。如果列中有重复项(特别是如果有许多重复项)

    可能更快,因为它可以在找到第一行后立即停止扫描


    您也可以在中使用,如@dezso演示,但在PostgreSQL中通常速度较慢。

    这很有效!使用左连接和where条件在左表中查找空值真是太棒了!如果可以的话,我会为不需要PL/SQL而加分。吹毛求疵:检查
    NULL
    的是正确的表,过程语言是
    PL/pgSQL
    或者干脆
    plpgsql
    PL/SQL
    是Oracle的野兽。我添加了一个替代方案供参考。感谢您的澄清。连接表位于右侧是有道理的。我要补充一点,我认为plpgsql是他们可能选择的最糟糕的名字。@jlunatgrad:他们肯定没有咨询任何人关于广告的第一个想法。:)我查过了,它也能用。我试图想出这样的东西,但我搞不懂语法。你让它看起来很简单。一个小提示,我不得不将最后一个from子句改为group_phones,这样它才能工作。
    BEGIN ISOLATION LEVEL SERIALIZABLE;
    INSERT ...
    COMMIT;
    
    LEFT JOIN tbl ON right_col = left_col WHERE right_col IS NULL
    
    WHERE NOT EXISTS (SELECT 1 FROM tbl WHERE right_col = left_col)