Comment faire une mise à jour + rejoindre dans PostgreSQL?

En gros, je veux faire ceci:

update vehicles_vehicle v join shipments_shipment s on v.shipment_id=s.id set v.price=s.price_per_vehicle; 

Je suis sûr que cela fonctionnerait dans MySQL (mon arrière-plan), mais cela ne semble pas fonctionner dans postgres. L’erreur que je reçois est:

 ERROR: syntax error at or near "join" LINE 1: update vehicles_vehicle v join shipments_shipment s on v.shi... ^ 

Il y a sûrement un moyen facile de le faire, mais je ne trouve pas la syntaxe appropriée. Alors, comment pourrais-je écrire ceci dans PostgreSQL?

La syntaxe UPDATE est la suivante:

 [AVEC [RECURSIVE] with_query [, ...]]
 UPDATE [ONLY] table [[AS] alias]
     SET {column = {expression |  DEFAULT} |
           (colonne [, ...]) = ({expression | DEFAULT} [, ...])} [, ...]
     [FROM from_list]
     [WHERE condition |  OENT CURRENT OF cursor_name]
     [RETOURNER * |  expression_sortie [[AS] nom_sortie] [, ...]

Dans ton cas, je pense que tu veux ça:

 UPDATE vehicles_vehicle AS v SET price = s.price_per_vehicle FROM shipments_shipment AS s WHERE v.shipment_id = s.id 

Laissez-moi vous expliquer un peu plus par mon exemple.

Tâche: informations correctes, où les abiturients (les étudiants sur le sharepoint quitter le secondaire) ont soumis des demandes d’admission à l’université plus tôt qu’ils n’ont obtenu des certificates scolaires (oui, ils ont obtenu des certificates augmenter la date de soumission de la candidature pour la date de délivrance du certificate.

Ainsi. prochaine déclaration semblable à MySQL:

 UPDATE applications a JOIN ( SELECT ap.id, ab.certificatee_issued_at FROM abiturients ab JOIN applications ap ON ab.id = ap.abiturient_id WHERE ap.documents_taken_at::date < ab.certificate_issued_at ) b ON a.id = b.id SET a.documents_taken_at = b.certificate_issued_at; 

Devient PostgreSQL-like de telle manière

 UPDATE applications a SET documents_taken_at = b.certificatee_issued_at -- we can reference joined table here FROM abiturients b -- joined table WHERE a.abiturient_id = b.id AND -- JOIN ON clause a.documents_taken_at::date < b.certificate_issued_at -- Subquery WHERE 

Comme vous pouvez le voir, la clause ON sous-requête originale JOIN est devenue l'une des conditions WHERE , qui est conjuguée à AND avec d'autres, qui ont été déplacées de la sous-requête sans aucune modification. Et il n'est plus nécessaire de JOIN table avec elle-même (comme c'était le cas dans la sous-requête).

La réponse de Mark Byers est optimale dans cette situation. Bien que dans des situations plus complexes, vous pouvez utiliser la requête select qui renvoie des rowids et des valeurs calculées et la joindre à la requête de mise à jour comme ceci:

 with t as ( -- Any generic query which returns rowid and corresponding calculated values select t1.id as rowid, f(t2, t2) as calculatedvalue from table1 as t1 join table2 as t2 on t2.referenceid = t1.id ) update t1 set value = t.calculatedvalue from t where id = t.rowid 

Cette approche vous permet de développer et de tester votre requête select et, en deux étapes, de la convertir en requête de mise à jour.

Donc, dans votre cas, la requête de résultat sera:

 with t as ( select v.id as rowid, s.price_per_vehicle as calculatedvalue from vehicles_vehicle v join shipments_shipment s on v.shipment_id = s.id ) update vehicles_vehicle set price = t.calculatedvalue from t where id = t.rowid 

Notez que les alias de colonnes sont obligatoires sinon PostgreSQL se plaindra de l’ambiguïté des noms de colonnes.

Pour ceux qui veulent faire une jointure, vous pouvez également utiliser:

 UPDATE a SET price = b_alias.unit_price FROM a as a_alias LEFT JOIN b as b_alias ON a_alias.b_fk = b_alias.id WHERE a_alias.unit_name LIKE 'some_value' AND a.id = a_alias.id; 

Vous pouvez utiliser le alias a_alias dans la section SET à droite du signe égal si nécessaire. Les champs à gauche du signe égal ne nécessitent pas de référence de table car ils sont considérés comme provenant de la table “a” d’origine.

Et c’est parti:

 update vehicles_vehicle v set price=s.price_per_vehicle from shipments_shipment s where v.shipment_id=s.id; 

Simple comme je pourrais le faire. Merci les gars!

Peut aussi faire ceci:

 update vehicles_vehicle set price=s.price_per_vehicle from vehicles_vehicle v join shipments_shipment s on v.shipment_id=s.id; 

Mais alors, vous avez la table de véhicule à deux resockets, et vous ne pouvez l’utiliser qu’une fois, et vous ne pouvez pas utiliser l’alias dans la partie “set”.

Voici un SQL simple qui met à jour Mid_Name sur la table Name3 en utilisant le champ Middle_Name de Nom:

 update name3 set mid_name = name.middle_name from name where name3.person_id = name.person_id;