Aktualisieren von Tabellenzeilen in Postgres mithilfe von Unterabfragen

304

Mit postgres 8.4 möchte ich die vorhandene Tabelle aktualisieren:

CREATE TABLE public.dummy
(
  address_id SERIAL,
  addr1 character(40),
  addr2 character(40),
  city character(25),
  state character(2),
  zip character(5),
  customer boolean,
  supplier boolean,
  partner boolean

)
WITH (
  OIDS=FALSE
);

Anfangs habe ich meine Abfrage mit der insert-Anweisung getestet:

insert into address customer,supplier,partner
SELECT  
    case when cust.addr1 is not null then TRUE else FALSE end customer, 
    case when suppl.addr1 is not null then TRUE else FALSE end supplier,
    case when partn.addr1 is not null then TRUE else FALSE end partner
from (
    SELECT *
        from address) pa
    left outer join cust_original cust
        on (pa.addr1=cust.addr1 and pa.addr2=cust.addr2 and pa.city=cust.city 
            and pa.state=cust.state and substring(cust.zip,1,5) = pa.zip  )
    left outer join supp_original suppl 
        on (pa.addr1=suppl.addr1 and pa.addr2=suppl.addr2 and pa.city=suppl.city 
                and pa.state=suppl.state and pa.zip = substring(suppl.zip,1,5))
    left outer join partner_original partn
        on (pa.addr1=partn.addr1 and pa.addr2=partn.addr2 and pa.city=partn.city
                  and pa.state=partn.state and pa.zip = substring(partn.zip,1,5) )
where pa.address_id = address_id

Als Neuling kann ich nicht in die Update-Anweisung konvertieren, dh vorhandene Zeilen mit Werten aktualisieren, die von der select-Anweisung zurückgegeben werden. Jede Hilfe wird sehr geschätzt.

Stackover
quelle
Haben Sie eine ID in der Adresstabelle, mit der festgestellt werden kann, ob eine Zeile vorhanden ist?
Andrey Adamovich
Ja, aber sein System wird generiert.
Stackover

Antworten:

683

Postgres erlaubt:

UPDATE dummy
SET customer=subquery.customer,
    address=subquery.address,
    partn=subquery.partn
FROM (SELECT address_id, customer, address, partn
      FROM  /* big hairy SQL */ ...) AS subquery
WHERE dummy.address_id=subquery.address_id;

Diese Syntax ist kein Standard-SQL, aber für diese Art von Abfrage viel praktischer als Standard-SQL. Ich glaube, Oracle akzeptiert (zumindest) etwas Ähnliches.

Andrew Lazarus
quelle
es scheint, dass ich etwas anderes versuche, z. Wenn 3 Bool-Spalten c1, c2, c3 vorhanden sind, werden diese zunächst alle auf false gesetzt. aber basierend auf Unterabfragen werden auf true gesetzt. Update-Set c1 = TRUE, wobei ID in (Unterabfrage1), Set c2 = TRUE, wo ID in (Unterabfrage2), Set c3 = True, wo ID in (Unterabfrage3). Ich war erfolgreich, als ich dies als 3 Updates aufteilte, aber ich bin nicht sicher, wie ich das Ergebnis mit einem einzigen Update erreichen kann. hoffe das macht Sinn.
Stackover
3
FWIW, Oracle akzeptiert dieses grundlegende Konstrukt, jedoch verschlechtert sich die Leistung des Updates tendenziell erheblich, wenn die Tabellen größer werden. Das ist aber in Ordnung, da Oracle auch die MERGE-Anweisung unterstützt.
Gsiems
3
Dies funktioniert überhaupt nicht in Postgresql 9.5, ich bekommeERROR: 42P01: relation "dummy" does not exist
user9645
73
dummymuss durch den Namen der Tabelle ersetzt werden, die Sie aktualisieren möchten. Bitte verstehen Sie Fragen und Antworten, bevor Sie sich bewerben.
Andrew Lazarus
1
Es kann erwähnenswert sein, dass es am Anfang der Abfrage nicht erforderlich ist, den Pfad zur Spalte auf der linken Seite nur am Ende anzugeben, da sich die Datenbank sonst mit ERROR beschwert: Die Spaltenreferenz "address_id" ist mehrdeutig
OJVM
126

Du bist hinter der UPDATE FROMSyntax her.

UPDATE 
  table T1  
SET 
  column1 = T2.column1 
FROM 
  table T2 
  INNER JOIN table T3 USING (column2) 
WHERE 
  T1.column2 = T2.column2;

Verweise

Brian Webster
quelle
2
Sollte die ausgewählte Antwort sein
Joshua Kifer
51

Wenn mit einem Join keine Leistungssteigerungen erzielt werden, bevorzuge ich aus Gründen der Lesbarkeit Common Table Expressions (CTEs):

WITH subquery AS (
    SELECT address_id, customer, address, partn
    FROM  /* big hairy SQL */ ...
)
UPDATE dummy
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE dummy.address_id = subquery.address_id;

IMHO etwas moderner.

steevee
quelle
1
Die Syntax ist nicht mit älteren Versionen von Postgres vor Version 9.1 kompatibel (siehe postgresql.org/docs/9.1/static/sql-update.html und die vorherigen Versionen). Ich bin also in Version 8.2 Wenn Sie die gesamte CTE / With-Anweisung nach dem FROM-Schlüsselwort in Klammern setzen, funktioniert dies.
Spcogg den zweiten
9

Es gibt viele Möglichkeiten, die Zeilen zu aktualisieren.

Wenn es um UPDATEdie Zeilen mit Unterabfragen geht, können Sie einen dieser Ansätze verwenden.

  1. Ansatz-1 [Verwenden der direkten Tabellenreferenz]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2>
WHERE
  <table1>.address_id=<table2>.address_i;

Erläuterung: Ist table1die Tabelle, die wir aktualisieren möchten, table2 ist die Tabelle, aus der wir den Wert erhalten, der ersetzt / aktualisiert werden soll. Wir verwenden eine FROMKlausel, um die table2Daten abzurufen . WHERE Klausel hilft dabei, die richtige Datenzuordnung festzulegen.

  1. Ansatz-2 [Verwenden von Unterabfragen]
UPDATE
  <table1>
SET
  customer=subquery.customer,
  address=subquery.address,
  partn=subquery.partn
FROM
  (
    SELECT
      address_id, customer, address, partn
    FROM  /* big hairy SQL */ ...
  ) AS subquery
WHERE
  dummy.address_id=subquery.address_id;

Erläuterung: Hier verwenden wir eine Unterabfrage innerhalb der FROMKlausel und geben ihr einen Alias. Damit es sich wie der Tisch verhält.

  1. Ansatz 3 [Verwenden mehrerer verbundener Tabellen]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2> as t2
  JOIN <table3> as t3
  ON
    t2.id = t3.id
WHERE
  <table1>.address_id=<table2>.address_i;

Erläuterung: Manchmal ist die Situation in dieser Tabellenverknüpfung so wichtig, dass die richtigen Daten für das Update abgerufen werden. Zu diesem Zweck können wir mit Postgres mehrere Tabellen innerhalb der FROMKlausel verbinden.

  1. Ansatz 4 [Using WITH-Anweisung]

    • 4.1 [Einfache Abfrage verwenden]
WITH subquery AS (
    SELECT
      address_id,
      customer,
      address,
      partn
    FROM
      <table1>;
)
UPDATE <table-X>
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE <table-X>.address_id = subquery.address_id;
  • 4.2 [Abfrage mit komplexem JOIN verwenden]
WITH subquery AS (
    SELECT address_id, customer, address, partn
    FROM
      <table1> as t1
    JOIN
      <table2> as t2
    ON
      t1.id = t2.id;
    -- You can build as COMPLEX as this query as per your need.
)
UPDATE <table-X>
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE <table-X>.address_id = subquery.address_id;

Erläuterung: Ab Postgres 9.1 wurde dieses ( WITH) Konzept eingeführt. Damit können wir komplexe Abfragen stellen und Wunschergebnisse generieren. Hier verwenden wir diesen Ansatz, um die Tabelle zu aktualisieren.

Ich hoffe, das wäre hilfreich. «

Mayur
quelle
1
update json_source_tabcol as d
set isnullable = a.is_Nullable
from information_schema.columns as a 
where a.table_name =d.table_name 
and a.table_schema = d.table_schema 
and a.column_name = d.column_name;
Pugazendhi Asaimuthu
quelle
1

@Mayur "4.2 [Verwenden einer Abfrage mit komplexem JOIN]" mit Common Table Expressions (CTEs) hat den Trick für mich getan.

WITH cte AS (
SELECT e.id, e.postcode
FROM employees e
LEFT JOIN locations lc ON lc.postcode=cte.postcode
WHERE e.id=1
)
UPDATE employee_location SET lat=lc.lat, longitude=lc.longi
FROM cte
WHERE employee_location.id=cte.id;

Hoffe das hilft ...: D.

Festus Ngor
quelle