J'utilise Python pour écrire dans une base de données PostgreSQL:
sql_string = "INSERT INTO hundred (name,name_slug,status) VALUES ("
sql_string += hundred + ", '" + hundred_slug + "', " + status + ");"
cursor.execute(sql_string)
Mais parce que certaines de mes lignes sont identiques, j'obtiens l'erreur suivante:
psycopg2.IntegrityError: duplicate key value
violates unique constraint "hundred_pkey"
Comment puis-je écrire une instruction SQL 'INSERT sauf si cette ligne existe déjà'?
J'ai vu des déclarations complexes comme celle-ci recommandées:
IF EXISTS (SELECT * FROM invoices WHERE invoiceid = '12345')
UPDATE invoices SET billed = 'TRUE' WHERE invoiceid = '12345'
ELSE
INSERT INTO invoices (invoiceid, billed) VALUES ('12345', 'TRUE')
END IF
Mais premièrement, est-ce exagéré pour ce dont j'ai besoin, et deuxièmement, comment puis-je exécuter l'un d'eux comme une simple chaîne?
postgresql
sql-insert
upsert
AP257
la source
la source
Réponses:
Postgres 9.5 (publié depuis le 2016-01-07) propose une commande "upsert" , également connue sous le nom de clause ON CONFLICT à INSERT :
Il résout de nombreux problèmes subtils que vous pouvez rencontrer lors de l'utilisation d'une opération simultanée, ce que d'autres réponses proposent.
la source
INSERT INTO distributors (did, dname) VALUES (7, 'Redline GmbH') ON CONFLICT (did) DO NOTHING;
(2) INSÉRER s'il n'existe pas d'autre MISE À JOUR -INSERT INTO distributors (did, dname) VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc') ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;
Ces exemples sont tirés du manuel - postgresql.org/docs/9.5/static/sql-insert.htmlIl y a une bonne façon de faire INSERT conditionnel dans PostgreSQL:
CAVEAT Cette approche n'est cependant pas fiable à 100% pour les opérations d'écriture simultanées . Il y a une très petite condition de course entre
SELECT
l'NOT EXISTS
anti-semi-jointure et leINSERT
lui - même. Il peut échouer dans de telles conditions.la source
RETURNS id
par exemple pourid
savoir si est inséré ou non?RETURNING id
au et de la requête et il renverra soit un nouvel identifiant de ligne, soit rien, si aucune ligne n'a été insérée.Une approche serait de créer une table non contrainte (pas d'index unique) pour insérer toutes vos données dans et faire une sélection distincte de celle pour faire votre insertion dans votre table de cent.
Si haut niveau serait. Je suppose que les trois colonnes sont distinctes dans mon exemple, donc pour l'étape 3, changez la jointure NOT EXITS pour ne joindre que les colonnes uniques de la table des cent.
Créez une table temporaire. Voir les documents ici .
INSÉRER les données dans la table temporaire.
Ajoutez des index à la table temporaire.
Faire l'insertion de la table principale.
la source
SELECT name,name_slug,status
ou*
SELECT DISTINCT name, name_slug, status FROM temp_data
?Malheureusement,
PostgreSQL
ne prend en charge niMERGE
niON DUPLICATE KEY UPDATE
, vous devrez donc le faire en deux déclarations:Vous pouvez l'envelopper dans une fonction:
et il suffit de l'appeler:
la source
INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred);
n'importe quel nombre de fois et cela continue d'insérer la ligne.CREATE TABLE hundred (name TEXT, name_slug TEXT, status INT); INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred); INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred); SELECT * FROM hundred
. Il y a un enregistrement.Vous pouvez utiliser les VALEURS - disponibles dans Postgres:
la source
Je sais que cette question remonte à un certain temps, mais j'ai pensé que cela pourrait aider quelqu'un. Je pense que la façon la plus simple de le faire est via un déclencheur. Par exemple:
Exécutez ce code à partir d'une invite psql (ou comme vous voulez exécuter des requêtes directement sur la base de données). Ensuite, vous pouvez insérer comme d'habitude à partir de Python. Par exemple:
Notez que comme @Thomas_Wouters déjà mentionné, le code ci-dessus tire parti des paramètres plutôt que de concaténer la chaîne.
la source
Il existe une bonne façon de faire INSERT conditionnel dans PostgreSQL en utilisant la requête WITH:
la source
C'est exactement le problème auquel je suis confronté et ma version est la 9.5
Et je le résous avec la requête SQL ci-dessous.
J'espère que cela aidera quelqu'un qui a le même problème avec la version> = 9.5.
Merci d'avoir lu.
la source
INSÉRER .. LÀ O NOT IL N'EXISTE PAS est une bonne approche. Et les conditions de concurrence peuvent être évitées par la transaction "enveloppe":
la source
C'est simple avec les règles:
Mais il échoue avec les écritures simultanées ...
la source
L'approche avec le plus de votes positifs (de John Doe) fonctionne en quelque sorte pour moi, mais dans mon cas, sur les 422 lignes attendues, je n'en reçois que 180. Je n'ai rien trouvé de mal et il n'y a aucune erreur, alors j'ai cherché un autre approche simple.
L'utilisation
IF NOT FOUND THEN
après unSELECT
fonctionne parfaitement pour moi.(décrit dans la documentation PostgreSQL )
Exemple de documentation:
la source
La classe de curseur psycopgs a l'attribut rowcount .
Vous pouvez donc d'abord essayer UPDATE et INSERT uniquement si le nombre de lignes est 0.
Mais selon les niveaux d'activité dans votre base de données, vous pouvez rencontrer une condition de concurrence critique entre UPDATE et INSERT où un autre processus peut créer cet enregistrement dans l'intervalle.
la source
Votre colonne "cent" semble être définie comme clé primaire et doit donc être unique ce qui n'est pas le cas. Le problème n'est pas avec, c'est avec vos données.
Je vous suggère d'insérer un identifiant comme type de série pour manipuler la clé primaire
la source
Si vous dites que plusieurs de vos lignes sont identiques, vous terminerez la vérification plusieurs fois. Vous pouvez les envoyer et la base de données déterminera si l'insérer ou non avec la clause ON CONFLICT comme suit
la source
Je cherchais une solution similaire, en essayant de trouver du SQL qui fonctionne aussi bien dans PostgreSQL que HSQLDB. (HSQLDB a rendu cela difficile.) En utilisant votre exemple comme base, c'est le format que j'ai trouvé ailleurs.
la source
Voici une fonction python générique qui, étant donné un nom de table, des colonnes et des valeurs, génère l'équivalent upsert pour postgresql.
importer json
la source
La solution en simple, mais pas immédiatement.
Si vous souhaitez utiliser cette instruction, vous devez apporter une modification à la base de données:
après ces modifications, "INSERT" fonctionnera correctement.
la source