Postgresql批插入或忽略
我有责任将我们的代码从sqlite切换到postgres。下面是我遇到的一个问题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函数来执行更
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)