Mettre à jour ou insérer (plusieurs lignes et colonnes) à partir d'une sous-requête dans PostgreSQL

106

J'essaye de faire quelque chose comme ça dans postgres:

  • UPDATE table1 SET (col1, col2) = (SELECT col2, col3 FROM othertable WHERE othertable.col1 = 123);

  • INSERT INTO table1 (col1, col2) VALUES (SELECT col1, col2 FROM othertable)

Mais le point 1 n'est pas possible même avec postgres 9.0 comme mentionné dans la documentation ( http://www.postgresql.org/docs/9.0/static/sql-update.html )

Le point 2 semble également ne pas fonctionner. j'obtiens l'erreur suivante: la sous-requête ne doit renvoyer qu'une seule colonne.

J'espère que quelqu'un a une solution de contournement pour moi. sinon, les requêtes prendront un certain temps :(.

FYI: J'essaie de sélectionner différentes colonnes de plusieurs tables et de les stocker dans une table temporaire, afin qu'une autre application puisse facilement récupérer les données préparées.

force
la source

Réponses:

175

Pour la MISE À JOUR

Utilisation:

UPDATE table1 
   SET col1 = othertable.col2,
       col2 = othertable.col3 
  FROM othertable 
 WHERE othertable.col1 = 123;

Pour l'INSERT

Utilisation:

INSERT INTO table1 (col1, col2) 
SELECT col1, col2 
  FROM othertable

Vous n'avez pas besoin de la VALUESsyntaxe si vous utilisez un SELECT pour remplir les valeurs INSERT.

Poneys OMG
la source
1
Est-il possible de combiner Update & Insert de sorte que si l'un échoue, l'autre sera utilisé sans générer d'erreur (indépendamment pour chaque ligne). Je pense que ce serait une solution plus complète à la question (par exemple: stackoverflow.com/a/6527838/781695 )
utilisateur
26

La réponse d'OMG Ponies fonctionne parfaitement, mais juste au cas où vous auriez besoin de quelque chose de plus complexe, voici un exemple de requête de mise à jour légèrement plus avancée:

UPDATE table1 
SET col1 = subquery.col2,
    col2 = subquery.col3 
FROM (
    SELECT t2.foo as col1, t3.bar as col2, t3.foobar as col3 
    FROM table2 t2 INNER JOIN table3 t3 ON t2.id = t3.t2_id
    WHERE t2.created_at > '2016-01-01'
) AS subquery
WHERE table1.id = subquery.col1;
David Namenyi
la source
1
You're the best :) :)
Ashwini
1
parfait. cela fonctionne mieux dans lequel vous devez choisir un sous-ensemble basé sur une condition impliquant la table mise à jour elle-même.
mythicalcoder
@David Namenyi pouvez-vous expliquer cette requête?
Chintan Pathak
15
UPDATE table1 SET (col1, col2) = (col2, col3) FROM othertable WHERE othertable.col1 = 123;
Walter
la source