Postgres:将一个表中的不同值插入到另一个带有约束的表中

Sor*_*rin 5 postgresql constraint distinct

我试图在删除重复条目的同时将数据从一个 PostgreSQL 9.3 表插入到另一个表。

我有两个包含电子邮件地址的表。

主表包含电子邮件和每个电子邮件地址的标签。组合(email, tag)必须是唯一的,为此有一个限制Unique(email, tag)

第二个表是从仅包含电子邮件地址的文本文件中动态创建的。那里有很多重复。

我需要将临时表中的数据导入主表而不破坏上述约束。对于包含电子邮件地址的特定文件,标签是恒定的。

表结构:

CREATE TABLE emails (   
  email character varying(128),
  tag bigint,
  CONSTRAINT "unique-tag-email" UNIQUE (email, tag) )
Run Code Online (Sandbox Code Playgroud)

CREATE TABLE emails_temp (email character varying(128)
Run Code Online (Sandbox Code Playgroud)

这是我的查询:

insert into emails(tag,email) 
select 
 655,t.email 
from 
 emails_temp as t 
where 
 not exists ( select email from emails where email = t.email )
Run Code Online (Sandbox Code Playgroud)

注意:655 只是某组电子邮件地址的标记。

这是我得到的错误:

错误:重复键值违反唯一约束“唯一标签电子邮件”SQL 状态:23505 详细信息:密钥(电子邮件,标签)=(user@hotmail.com,655)已经存在。

文件中确实有两个电子邮件地址 user@hotmail.com。

废话不多说,因为这个错误,主表(email)里什么都没有添加。

我究竟做错了什么?

Erw*_*ter 5

3种可能的重复类型:

  1. 批量插入行内的重复项。

  2. 在插入的行和现有的行之间重复。

  3. 在插入的行和来自其他事务的同时插入/更新的行之间重复。

就像我在这个密切相关的答案中解释的那样:

但是自从 Postgres 9.5 引入 UPSERT ( )以来,对于2.3. 来说事情变得更容易了INSERT .. ON CONFLICT DO NOTHING

INSERT INTO emails(tag,email)
SELECT DISTINCT 655, email
FROM   emails_temp
ON CONFLICT (email) DO NOTHING;
Run Code Online (Sandbox Code Playgroud)

如果您的重复项仅源于源 ( 1. )中的重复条目,如您所指出的,那么您只需要DISTINCT. 适用于任何版本的 Postgres:

INSERT INTO emails(tag,email)
SELECT DISTINCT 655, email
FROM   emails_temp;
Run Code Online (Sandbox Code Playgroud)