web-dev-qa-db-ja.com

Postgres:制約を設定して、1つのテーブルから別のテーブルに個別の値を挿入します

重複するエントリを削除しながら、PostgreSQL 9.3のテーブルから別のテーブルにデータを挿入しようとしています。

メールアドレスを含む2つのテーブルがあります。

メインテーブルには、メールと各メールアドレスのタグが含まれています。 _(email, tag)_の組み合わせは一意である必要があり、これにはUnique(email, tag)の制約があります。

2番目のテーブルは、電子メールアドレスのみを含むテキストファイルからその場で作成されます。そこには多くの重複があります。

上記の制約を破ることなく、一時テーブルからメインテーブルにデータをインポートする必要があります。メールアドレスを含む特定のファイルでは、タグは一定です。

テーブル構造:

_CREATE TABLE emails (   
  email character varying(128),
  tag bigint,
  CONSTRAINT "unique-tag-email" UNIQUE (email, tag) )
_

そして

_CREATE TABLE emails_temp (email character varying(128)
_

これが私のクエリです:

_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 )
_

注:655は、メールアドレスの特定のグループのタグにすぎません。

これは私が得るエラーです:

エラー:重複するキー値が一意の制約「unique-tag-email」に違反していますSQL状態:23505詳細:キー(email、tag)=([email protected]、655)はすでに存在します。

実際、ファイルには2つのメールアドレス[email protected]があります。

言うまでもなく、このエラーのため、メインテーブル(電子メール)には何も追加されていません。

何が悪いのですか?

5
Sorin

3可能な種類の重複があります:

  1. 一括挿入の行内で重複します。

  2. 挿入された行と既存の行の間で複製します。

  3. 挿入された行と、他のトランザクションから同時に挿入/更新された行の間で重複します。

私がこの密接に関連した答えで説明したように:

しかし、2。3.Postgres 9.5からUPSERT(INSERT .. ON CONFLICT DO NOTHING)。

INSERT INTO emails(tag,email)
SELECT DISTINCT 655, email
FROM   emails_temp
ON CONFLICT (email) DO NOTHING;

指定したように、重複がソースの重複エントリ(1。)にのみ起因する場合、必要なのはDISTINCTだけです。 Postgresのどのバージョンでも機能します。

INSERT INTO emails(tag,email)
SELECT DISTINCT 655, email
FROM   emails_temp;
5