it-swarm.com.de

Wie mache ich ein Update + Join in PostgreSQL?

Grundsätzlich möchte ich Folgendes tun:

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

Ich bin mir ziemlich sicher, dass dies in MySQL (meinem Hintergrund) funktionieren würde, aber es scheint nicht in Postgres zu funktionieren. Der Fehler, den ich erhalte, ist:

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

Sicher gibt es eine einfache Möglichkeit, dies zu tun, aber ich kann die richtige Syntax nicht finden. Wie würde ich das in PostgreSQL schreiben?

396
mpen

Die UPDATE-Syntax lautet:

 [WITH [RECURSIVE] with_query [ ...]] 
 UPDATE [ONLY] Tabelle [[AS] Alias] 
 SET {column = {Ausdruck | STANDARD} | 
 (Spalte [ ...]) = ({Ausdruck | DEFAULT} [ ...])} [ ...] 
 [FROM from_list] 
 [WO Bedingung | WHERE CURRENT VON Cursorname] 
 [RÜCKKEHR * | Ausgabeausdruck [[AS] Ausgabenname] [ ...]] 

In Ihrem Fall glaube ich, dass Sie das wollen:

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

Lassen Sie mich an meinem Beispiel etwas mehr erklären.

Aufgabe: korrekte Informationen, wo Abiturienten (Studenten, die kurz vor dem Abitur stehen) früher Anträge an die Universität gestellt haben, als sie Schulzeugnisse erhalten haben (ja, sie haben früher Zertifikate erhalten, als sie ausgestellt wurden (nach dem Datum des Zertifikats). Also werden wir es tun Antragsübermittlungsdatum erhöhen, um das Zertifikatausstellungsdatum anzupassen. 

Somit. nächste MySQL-ähnliche Anweisung:

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;

Wird so zu PostgreSQL-ähnlich

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

Wie Sie sehen können, ist die JOIN-Klausel der ursprünglichen Unterabfrage ON zu einer der WHERE-Bedingungen geworden, die von AND mit anderen zusammengestellt wird, die aus der Unterabfrage ohne Änderungen verschoben wurden. Und es ist nicht mehr nötig, JOIN mit sich selbst (wie in der Unterabfrage) zu tabellen.

108
Envek

Die Antwort von Mark Byers ist in dieser Situation optimal. In komplexeren Situationen können Sie jedoch die Auswahlabfrage verwenden, die Zeilen-IDs und berechnete Werte zurückgibt, und diese an die Aktualisierungsabfrage anfügen.

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

Mit diesem Ansatz können Sie Ihre Auswahlabfrage entwickeln und testen und diese in zwei Schritten in die Aktualisierungsabfrage konvertieren.

In Ihrem Fall lautet die Ergebnisabfrage also:

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

Beachten Sie, dass Spaltenaliasnamen obligatorisch sind, andernfalls wird sich PostgreSQL über die Mehrdeutigkeit der Spaltennamen beschweren.

96
Alvin

Für diejenigen, die tatsächlich eine JOIN ausführen möchten, können Sie auch Folgendes verwenden:

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;

Sie können a_alias im Abschnitt SET auf der rechten Seite des Gleichheitszeichens verwenden, wenn dies erforderlich ist .. _ Die Felder auf der linken Seite des Gleichheitszeichens erfordern keine Tabellenreferenz, da sie vom ursprünglichen "a" stammen Tabelle.

45
Fast Engy

Auf geht's:

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

So einfach wie ich es schaffen könnte. Danke Leute!

Kann das auch tun:

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

Aber dann haben Sie den Fahrzeugtisch zweimal drin, und Sie dürfen ihn nur einmal als Aliasnamen verwenden, und Sie können den Alias ​​nicht im "Set" -Bereich verwenden.

5
mpen

Für diejenigen, die einen JOIN durchführen möchten, der NUR die Zeilen aktualisiert, die der Join zurückgibt, verwenden Sie:

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;

Dies wurde oben erwähnt, aber nur durch einen Kommentar. Da es entscheidend ist, das richtige Ergebnis zu erhalten, wird eine neue Antwort veröffentlicht, die funktioniert

2
Nate Smith

Der Link unten hat ein Beispiel, das auflöst und hilft, die Verwendung von update und join mit Postgres zu verstehen.

UPDATE product
SET net_price = price - price * discount
FROM
product_segment
WHERE
product.segment_id = product_segment.id;

Siehe: http://www.postgresqltutorial.com/postgresql-update-join/

0
Alessandro

Hier ist eine einfache SQL, die Mid_Name in der Name3-Tabelle mit dem Feld Middle_Name aus Name aktualisiert:

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