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 avec MySQL (mon expérience), mais cela ne semble pas fonctionner avec 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 existe sûrement un moyen facile de le faire, mais je ne trouve pas la syntaxe appropriée. Alors, comment pourrais-je écrire cela dans PostgreSQL?
La syntaxe UPDATE est la suivante:
[WITH [RECURSIVE] with_query [ ...]] UPDATE [ONLY] table [alias [[AS]]] SET {colonne = {expression | DEFAULT} | (colonne [ ...]) = ({expression | DEFAULT} [ ...])} [ ...] [FROM from_list] [OERE condition | WHERE CURRENT OF nom_curseur] [RETOURNANT * | expression_sortie [[AS] nom_sortie] [ ...]]
Dans votre cas, je pense que vous voulez ceci:
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 élèves (les étudiants sur le point de quitter l’école secondaire) ont soumis leurs demandes à l’université plus tôt, qu’ils ont obtenu des certificats d’études (oui, ils ont obtenu des certificats plus tôt que ce qu’ils ont été délivrés (date spécifiée)). augmenter la date de soumission de la demande pour correspondre à la date de délivrance du certificat.
Ainsi. prochaine déclaration de type MySQL:
UPDATE applications a
JOIN (
SELECT ap.id, ab.certificate_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 comme PostgreSQL
UPDATE applications a
SET documents_taken_at = b.certificate_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 constater, la clause JOIN
de la sous-requête originale ON
est devenue l’une des conditions WHERE
, qui est créée par AND
avec d’autres, qui ont été déplacées de la sous-requête sans modification. Et il n'y a plus besoin de JOIN
table avec lui-même (comme c'était le cas dans la sous-requête).
La réponse de Mark Byers est la solution optimale dans cette situation. Bien que dans des situations plus complexes, vous pouvez prendre la requête select qui renvoie les ID de ligne et les valeurs calculées et la lier à la requête de mise à jour comme suit:
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 sélectionnée 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 réellement faire une JOIN
, 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 a_alias dans la section SET
à droite du signe égal, si nécessaire . Les champs situés à gauche du signe égal ne nécessitent pas de référence à une table car ils sont réputés provenir de l'original "a". table.
Et c'est parti:
update vehicles_vehicle v
set price=s.price_per_vehicle
from shipments_shipment s
where v.shipment_id=s.id;
Aussi simple que je pouvais 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 ensuite, vous avez la table de véhicules deux fois, et vous n'êtes autorisé à la nommer qu'une fois, et vous ne pouvez pas utiliser l'alias dans la partie "set".
Pour ceux qui souhaitent faire une jointure mettant à jour UNIQUEMENT les lignes que votre jointure retourne, utilisez:
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
--the below line is critical for updating ONLY joined rows
AND a.pk_id = a_alias.pk_id;
Cela a été mentionné ci-dessus, mais uniquement par le biais d'un commentaire. Étant donné qu'il est essentiel d'obtenir le résultat correct en affichant une NOUVELLE réponse qui fonctionne.
Le lien ci-dessous contient un exemple qui résout et aide à comprendre mieux comment utiliser update
et join
avec postgres.
UPDATE product
SET net_price = price - price * discount
FROM
product_segment
WHERE
product.segment_id = product_segment.id;
Voir: http://www.postgresqltutorial.com/postgresql-update-join/
Voici un SQL simple qui met à jour Mid_Name sur la table Name3 à l'aide du champ Middle_Name de Name:
update name3
set mid_name = name.middle_name
from name
where name3.person_id = name.person_id;