UPDATE … FROM în PostgreSQL

Modificare date și tranzacții PostgreSQL 8.2+ (standard în PostgreSQL 15–17)

Actualizează rândurile unui tabel folosind date dintr-un alt tabel sau dintr-o listă VALUES prin clauza FROM.

Sintaxă SQL
UPDATE tabel_tinta t SET col = s.val FROM tabel_sursa s WHERE t.id = s.id RETURNING t.*;

Ce face UPDATE ... FROM

În timp ce alte sisteme SQL folosesc sintaxa UPDATE t1 JOIN t2 ..., PostgreSQL utilizează clauza UPDATE tabel_tinta SET ... FROM tabel_sursa WHERE ... pentru a actualiza rânduri pe baza datelor din alte tabele, vederi sau liste VALUES.

Tabelul țintă este specificat imediat după UPDATE, iar tabelele suplimentare se enumeră în FROM, legătura dintre ele realizându-se în clauza WHERE.

Clauze, operatori și argumente

Clauză / Operator Descriere
UPDATE tabel_tinta [AS t] Tabelul ale cărui rânduri vor fi modificate (aliasul ajută la dezambiguizarea coloanelor).
SET col = expresie Atribuie noile valori; în expresie pot fi folosite și coloane din tabelele specificate în FROM.
FROM sursa1 [, sursa2 ...] Aduce în context unul sau mai multe tabele, subinterogări sau liste (VALUES ...).
WHERE t.cheie = s.cheie Condiția de joncțiune și filtrare; fără ea, fiecare rând din țintă s-ar potrivi cu toate rândurile din sursă.
RETURNING ... Returnează rândurile actualizate (cu noile valori din tabelul țintă, dar poate include și coloane din FROM).

Exemple

Exemplul 1: Actualizarea prețurilor dintr-un tabel temporar de import cu UPDATE … FROM

Aplicăm noile prețuri din tabelul import_preturi în tabelul produse și afișăm atât prețul nou, cât și diferența.

UPDATE produse p
SET pret = imp.pret_nou,
    actualizat_la = NOW()
FROM import_preturi imp
WHERE p.sku = imp.sku
  AND p.pret <> imp.pret_nou
RETURNING p.sku, p.denumire, p.pret AS pret_actualizat;

Rezultat interogare

     sku     |        denumire        | pret_actualizat 
-------------+------------------------+-----------------
 MON-27-4K   | Monitor IPS 27 inch 4K |         1599.00
 KBD-MECH-RO | Tastatură Mecanică RO  |          399.00
(2 rows)

UPDATE 2

Exemplul 2: Actualizare în masă cu valori diferite per ID folosind FROM (VALUES …)

Schimbăm ordinea de afișare pentru 3 categorii distincte într-o singură interogare rapidă.

UPDATE categorii c
SET ordine_afisare = v.ordine_noua
FROM (VALUES
    (10, 1),
    (15, 2),
    (12, 3)
) AS v(id, ordine_noua)
WHERE c.id = v.id
RETURNING c.id, c.nume, c.ordine_afisare;

Rezultat interogare

 id |    nume    | ordine_afisare 
----+------------+----------------
 10 | Laptopuri  |              1
 15 | Monitoare  |              2
 12 | Periferice |              3
(3 rows)

UPDATE 3

Greșeli frecvente

  • Repetarea tabelului țintă în clauza FROM (ex: UPDATE produse p SET ... FROM produse p JOIN ...): în PostgreSQL aceasta creează un self-join neintenționat; tabelul țintă trebuie pus doar după UPDATE.
  • Dacă un rând din tabelul țintă se potrivește cu mai multe rânduri din tabelul FROM, rezultatul este nedeterminist (doar unul dintre rândurile sursă va fi folosit pentru actualizare).

Comenzi și funcții înrudite

  • ON CONFLICT DO UPDATE (UPSERT): Rezolvă atomic conflictele de cheie unică la inserare: ignoră rândul duplicat sau îl actualizează pe loc.
  • DELETE ... USING și TRUNCATE: Șterge rânduri filtrate prin joncțiuni cu DELETE … USING sau golește instantaneu tabele întregi cu TRUNCATE.
  • INSERT INTO ... RETURNING: Inserează unul sau mai multe rânduri și returnează imediat valorile generate (ID-uri, timestamp-uri) fără o interogare suplimentară.