aktualizowanie wierszy tabeli w postgresie za pomocą podzapytania

301

Używając postgres 8.4, moim celem jest aktualizacja istniejącej tabeli:

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
);

Początkowo przetestowałem moje zapytanie przy użyciu instrukcji insert:

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

będąc nowicjuszem nie powiodło mi się przekształcenie instrukcji update, tj. aktualizacja istniejących wierszy o wartości zwrócone przez instrukcję select Każda pomoc jest bardzo ceniona.

nakładanie
źródło
czy masz jakiś identyfikator w tabeli adresowej, którego można użyć do ustalenia, czy wiersz istnieje?
Andrey Adamovich,
tak, ale wygenerowałem system.
stackover

Odpowiedzi:

681

Postgres pozwala:

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;

Ta składnia nie jest standardowym SQL, ale jest znacznie wygodniejsza dla tego typu zapytań niż standardowy SQL. Wierzę, że Oracle (przynajmniej) akceptuje coś podobnego.

Andrew Lazarus
źródło
wygląda na to, że próbuję czegoś innego na przykład. jeśli istnieją 3 kolumny bool c1, c2, c3 wszystkie początkowo ustawione na fałsz. ale na podstawie podzapytania są ustawione na true. zestaw aktualizacji c1 = PRAWDA gdzie id w (subquery1), ustaw c2 = PRAWDA gdzie id w (subquery2), ustaw c3 = True gdzie id w (subquery3). Udało mi się, gdy podzielę to na 3 aktualizacje, ale nie jestem pewien, jak osiągnąć wynik za pomocą jednej aktualizacji. mam nadzieję, że to ma sens.
nakładanie
3
FWIW, Oracle akceptuje tę podstawową konstrukcję, jednak wydajność aktualizacji ma tendencję do poważnego obniżania się w miarę powiększania się tabel. Nie szkodzi, ponieważ Oracle obsługuje również instrukcję MERGE.
gsiems
3
To całkowicie nie działa w postgresql 9.5, otrzymujęERROR: 42P01: relation "dummy" does not exist
user9645
72
dummymusi zostać zastąpiony nazwą tabeli, którą próbujesz zaktualizować. Proszę zrozumieć pytanie i odpowiedź przed próbą złożenia wniosku.
Andrew Lazarus
1
Warto wspomnieć, że na początku zapytania nie jest konieczne określenie ścieżki do kolumny po lewej stronie, tylko na końcu, w przeciwnym razie db będzie skarżyć się na BŁĄD: odwołanie do kolumny „adres_id” jest niejednoznaczne
OJVM,
126

Poszukujesz UPDATE FROMskładni.

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

Bibliografia

Brian Webster
źródło
2
Powinna być wybrana odpowiedź
Joshua Kifer
51

Jeśli nie ma wzrostu wydajności przy użyciu sprzężenia, wolę wspólne wyrażenia tabelowe (CTE) dla czytelności:

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 jest trochę bardziej nowoczesny.

steevee
źródło
1
Składnia nie jest kompatybilna ze starszymi wersjami Postgresa przed wersją 9.1 (patrz postgresql.org/docs/9.1/static/sql-update.html i poprzednie wersje) Mam wersję 8.2, więc masz umieścić całą instrukcję CTE / With w nawiasach po słowie kluczowym FROM i będzie działać.
Spcogg drugi
9

Istnieje wiele sposobów aktualizowania wierszy.

Jeśli chodzi o UPDATEwiersze za pomocą podkwerend, możesz użyć dowolnego z tych podejść.

  1. Podejście-1 [Korzystanie z bezpośredniego odwołania do tabeli]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2>
WHERE
  <table1>.address_id=<table2>.address_i;

Objaśnienie: table1to tabela, którą chcemy zaktualizować, table2 to tabela, z której otrzymamy wartość do zastąpienia / aktualizacji. Używamy FROMklauzuli, aby pobrać table2dane. WHERE klauzula pomoże ustawić odpowiednie mapowanie danych.

  1. Podejście-2 [Korzystanie z SubQueries]
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;

Objaśnienie: Tutaj używamy podzapytania wewnątrz FROMklauzuli i nadajemy jej alias. Aby działał jak stół.

  1. Podejście-3 [Korzystanie z wielu połączonych tabel]
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;

Objaśnienie: Czasami mamy do czynienia z sytuacją, w której dołączenie do tabeli jest tak ważne, aby uzyskać odpowiednie dane do aktualizacji. W tym celu Postgres pozwala nam łączyć wiele tabel wewnątrz FROMklauzuli.

  1. Podejście-4 [Korzystanie z instrukcji WITH]

    • 4.1 [Korzystanie z prostego zapytania]
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 [Korzystanie z zapytania ze złożonym JOIN]
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;

Objaśnienie: Od wersji Postgres 9.1 wprowadzono tę ( WITH) koncepcję. Za pomocą tego możemy zadawać dowolne złożone zapytania i generować pożądany rezultat. W tym przypadku wykorzystujemy to podejście do aktualizacji tabeli.

Mam nadzieję, że byłoby to pomocne

Mayur
źródło
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
źródło
1

@Mayur „4.2 [Używanie zapytania ze złożonym JOIN]” z Common Table Expressions (CTE) załatwiło sprawę .

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;

Mam nadzieję, że to pomaga ...: D

Festus Ngor
źródło