サブクエリを使用してpostgresのテーブル行を更新する


304

postgres 8.4を使用して、私の目標は既存のテーブルを更新することです:

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

最初に、挿入ステートメントを使用してクエリをテストしました。

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

初心者なので、更新ステートメントへの変換に失敗しています。つまり、selectステートメントによって返された値で既存の行を更新しています。どんな助けでも大歓迎です。


行が存在することを決定するために使用できるアドレステーブルにIDの種類がありますか?
Andrey Adamovich、2011

はい私はしますが、そのsysが生成されました。
stackover

回答:


683

Postgresでは次のことが可能です。

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;

この構文は標準SQLではありませんが、このタイプのクエリには標準SQLよりもはるかに便利です。Oracleは(少なくとも)同様のことを受け入れます。


たとえば、私は少し違うことに挑戦しているようです。3つのブール列がある場合、c1、c2、c3はすべて最初にfalseに設定されます。しかし、サブクエリに基づいてtrueに設定されます。set c1 = TRUE where id in(subquery1)、set c2 = TRUE where id in(subquery2)、set c3 = True where id in(subquery3)を更新します。これを3つの更新に分割したときに成功しましたが、1つの更新で結果を得る方法がわかりません。これが意味をなすことを願っています。
スタックオーバー、2011年

3
FWIW、Oracleはその基本的な構成を受け入れますが、テーブルが大きくなると、更新のパフォーマンスが大幅に低下する傾向があります。OracleもMERGEステートメントをサポートしているため、問題ありません。
gsiems 2015年

3
これは完全にpostgresql 9.5では機能しません、私は得ますERROR: 42P01: relation "dummy" does not exist
user9645

73
dummy更新しようとしているテーブルの名前に置き換える必要があります。応募する前に質問と回答を理解してください。
Andrew Lazarus

1
クエリの最初に左側の列へのパスを指定する必要はなく、最後にのみ指定する必要があります。そうしないと、dbはエラーを表示します。列参照 "address_id"があいまいです
OJVM


51

結合を使用してもパフォーマンスが向上しない場合は、読みやすくするために共通テーブル式(CTE)を使用します。

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;

私見はもう少しモダン。


1
構文はv9.1より前の古いバージョンのPostgresと互換性がありません(postgresql.org/docs/9.1/static/sql-update.htmlと以前のバージョンを参照)私はv8.2を使用しているので、 FROMキーワードの後の括弧内にCTE / Withステートメント全体を置くと、機能します。
Spcogg、2017

9

行を更新するには多くの方法があります。

UPDATEサブクエリを使用する行に関しては、これらのアプローチのいずれかを使用できます。

  1. アプローチ1 [直接テーブル参照を使用]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2>
WHERE
  <table1>.address_id=<table2>.address_i;

説明:table1は、更新table2 するテーブルです。は、置換/更新される値を取得するテーブルです。FROM節を使用して、table2のデータをフェッチしています。WHERE 句は、適切なデータマッピングを設定するのに役立ちます。

  1. アプローチ2 [サブクエリの使用]
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;

説明:ここでは、FROM句内でサブクエリを使用し、それにエイリアスを与えています。テーブルのように振る舞うように。

  1. アプローチ3 [複数の結合テーブルの使用]
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;

説明:場合によっては、更新に適切なデータを取得するためにテーブル結合が非常に重要であるという状況に直面することがあります。これを行うために、PostgresではFROM節内の複数のテーブルを結合できます。

  1. アプローチ4 [WITHステートメントの使用]

    • 4.1 [単純なクエリの使用]
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 [複雑な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;

説明:Postgres 9.1から、this(WITH)の概念が導入されました。それを使用して、複雑なクエリを実行し、欲望の結果を生成できます。ここでは、このアプローチを使用してテーブルを更新しています。

これがお役に立てば幸いです。😊


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;

1

@Mayur 「4.2 [複雑なJOINでのクエリの使用]」CTE(Common Table Expressions)がうまく機能しました。

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;

これが役に立てば幸い...:D

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.