PostgreSQLでUPDATE。

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

業務で使用するのはRedshiftが中心ですが、ローカル環境でちょっと試したい場合は元になっているPostgreSQLを使っています。
基本INSERTばかりであまりUPDATEを使ってませんでしたが、調べたので書いておきます。

環境

Mac OSX 10.10.5 Yosemite
PostgreSQL 9.5.1

使用するテーブル

/*スキーマ作成*/
CREATE SCHEMA blog;

/*テーブルA*/
CREATE TABLE blog.table_a (
  id SERIAL
  ,val INTEGER
  ,PRIMARY KEY(id)
);
INSERT INTO blog.table_a VALUES
(1, 101), (2, 102), (3, 103);

/*テーブルB*/
CREATE TABLE blog.table_b (
  id SERIAL
  ,val INTEGER
  ,PRIMARY KEY(id)
);
INSERT INTO blog.table_b VALUES
(0, 100), (2, 112), (3, 113);

/*テーブルC*/
CREATE TABLE blog.table_c (
  id SERIAL
  ,val INTEGER
  ,PRIMARY KEY(id)
);
INSERT INTO blog.table_c VALUES
(2, 212), (3, 313);
postgres=# select * from blog.table_a;    
 id | val 
----+-----
  1 | 101
  2 | 102
  3 | 103
(3 rows)

postgres=# select * from blog.table_b;
 id | val 
----+-----
  0 | 100
  2 | 112
  3 | 113
(3 rows)

postgres=# select * from blog.table_c;
 id | val 
----+-----
  2 | 212
  3 | 313
(2 rows)

1、通常のWHEREを使用したUPDATE

テーブルAのidが1のレコードのidとvalを更新。

SQL

UPDATE blog.table_a
SET id = 0, val = 999
WHERE id = 1;

複数カラムを更新できます。

実行結果

postgres=# select * from blog.table_a order by id;  
 id | val 
----+-----
  0 | 999
  2 | 102
  3 | 103
(3 rows)

id「1」が「0」に更新され、valも「999」に更新されました。

2、FROM、WHEREを使用したUPDATE

テーブルBの中で、テーブルAのidが一致するvalを更新する。

SQL

UPDATE blog.table_a
SET val = B.val
FROM blog.table_b AS B
WHERE table_a.id = B.id;

UPDATE句のテーブルには別名を設定できないので、WHERE句で「table_a.id」などと書かないといけません。

実行結果

postgres=# select * from blog.table_a;  
 id | val 
----+-----
  0 | 100
  2 | 112
  3 | 113
(3 rows)

テーブルBのidは「0」「2」「3」を持っているので全てのvalが更新されました。

3、FROM、JOINを使用したUPDATE

テーブルBとテーブルCをidで結合した結果の中で、テーブルAのidが一致するvalを更新

SQL

UPDATE blog.table_a
SET val = C.val
FROM blog.table_b AS B
       LEFT OUTER JOIN blog.table_c AS C ON C.id = B.id
WHERE blog.table_a.id = C.id;

テーブルAのidが同じ場合のみ、テーブルBとテーブルCを結合した結果の値で更新。

実行結果

postgres=# select * from blog.table_a;  
 id | val 
----+-----
  0 | 100
  2 | 212
  3 | 313
(3 rows)

テーブルCのidは「2」「3」をもっているので、一致するレコードのvalのみ更新されました。

さいごに

FROMを使用した場合に条件に一致した項目が複数存在すると、思わぬ結果になりますので注意が必要です。