web-dev-qa-db-fra.com

Ignorer les clés en double lors de la copie de postgresql

Je dois vider une grande quantité de données d'un fichier vers une table PostgreSQL. Je sais qu'il ne supporte pas 'Ignore' 'replace' etc. comme dans MySql. Presque toutes les publications à ce sujet sur le Web suggéraient la même chose, par exemple, vider les données dans une table temporaire, puis faire un "insérer ... sélectionnez ... où n'existe pas ...".

Cela n’aidera pas dans un cas où les données du fichier contenaient elles-mêmes des clés primaires dupliquées ..___ Tout corps a-t-il une idée de la façon de gérer cela dans PostgreSQL?

P.S. Je le fais à partir d'un programme Java, si cela aide

40
Kam

Utilisez la même approche que celle que vous avez décrite, mais DELETE (ou groupe, ou modifiez ...) dupliquez PK dans la table temporaire avant le chargement dans la table principale.

Quelque chose comme:

CREATE TEMP TABLE tmp_table 
ON COMMIT DROP
AS
SELECT * 
FROM main_table
WITH NO DATA;

COPY tmp_table FROM 'full/file/name/here';

INSERT INTO main_table
SELECT DISTINCT ON (PK_field) *
FROM tmp_table
ORDER BY (some_fields)

Détails: CREATE TABLE AS , COPY , DISTINCT ON

51
Igor Romanchenko

PostgreSQL 9.5 a maintenant la fonctionnalité upsert . Vous pouvez suivre les instructions d'Igor, sauf que la dernière instruction INSERT inclut la clause ON CONFLICTO DOH RING.

INSERT INTO main_table
SELECT *
FROM tmp_table
ON CONFLICT DO NOTHING
27
Alan Simmons

La réponse d’Igor m’a beaucoup aidé, mais j’ai aussi rencontré le problème mentionné par Nate dans son commentaire. Ensuite, j'ai eu le problème — peut-être en plus de la question ici — que les nouvelles données contenaient non seulement des doublons internes, mais aussi des doublons avec les données existantes. Ce qui a fonctionné pour moi a été le suivant.

CREATE TEMP TABLE tmp_table AS SELECT * FROM newsletter_subscribers;
COPY tmp_table (name, email) FROM stdin DELIMITER ' ' CSV;
SELECT count(*) FROM tmp_table;  -- Just to be sure
TRUNCATE newsletter_subscribers;
INSERT INTO newsletter_subscribers
    SELECT DISTINCT ON (email) * FROM tmp_table
    ORDER BY email, subscription_status;
SELECT count(*) FROM newsletter_subscribers;  -- Paranoid again

Les doublons internes et externes deviennent identiques dans le tmp_table et la partie DISTINCT ON (email) les supprime. Le ORDER BY s'assure que la ligne souhaitée vient en premier dans le jeu de résultats et DISTINCT puis rejette toutes les autres lignes.

11
Denis Drescher

Insérer dans une table temporaire regroupée par la clé pour vous débarrasser des doublons

et ensuite insérer s'il n'existe pas

0
Jester