PostgreSQLを使用して同じクエリの複数の行を更新する


190

1つのステートメントでPostgreSQLの複数の行を更新しようとしています。次のようなことをする方法はありますか?

UPDATE table 
SET 
 column_a = 1 where column_b = '123',
 column_a = 2 where column_b = '345'

私はそのページでそれを見つけようとし続けていますが、それを得ることができません。1つのwhereステートメントを使用して複数の行を更新できる場所はわかりますが、独自のwhereステートメントを使用して複数の行をそれぞれ更新する方法はわかりません。私はグーグルも検索しましたが、本当の明確な答えが見つからなかったので、誰かがこれについて明確な例を提供できることを望んでいました。
newUserNameHere

すみません、私の間違いです。更新しました。
zero323

回答:


423

update ... from構文とマッピングテーブルを使用することもできます。複数の列を更新する場合は、はるかに一般化できます。

update test as t set
    column_a = c.column_a
from (values
    ('123', 1),
    ('345', 2)  
) as c(column_b, column_a) 
where c.column_b = t.column_b;

列はいくつでも追加できます。

update test as t set
    column_a = c.column_a,
    column_c = c.column_c
from (values
    ('123', 1, '---'),
    ('345', 2, '+++')  
) as c(column_b, column_a, column_c) 
where c.column_b = t.column_b;

sql fiddle demo


10
また、正しいデータ型を指定する必要がある場合もあります。日付の例:... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...でさらに詳細PostgreSQLのドキュメント
ホセ・Andias

うまくいきました、明確にしていただきありがとうございます!このためのPostgresのドキュメントは、少し紛らわしい読みになります。
skwidbreth 2016年

51

@Romanのソリューションに基づいて、複数の値を設定できます。

update users as u set -- postgres FTW
  email = u2.email,
  first_name = u2.first_name,
  last_name = u2.last_name
from (values
  (1, 'hollis@weimann.biz', 'Hollis', 'O\'Connell'),
  (2, 'robert@duncan.info', 'Robert', 'Duncan')
) as u2(id, email, first_name, last_name)
where u2.id = u.id;

4
これは彼の解決策のようです... UPDATE FROM(VALUES ...)WHERE。どのようにのみ基づいていますか?
エヴァンキャロル

14
変数名を使用すると、何が起こっているのかを理解しやすくなるので、私はこの答えを好みます。
Jon Lemmon

ワオ。正確で明確。このようなものをGoLangに実装しようとしています。それで、値の場所に構造体の配列を渡すことができますか?このようなもの、from (values $1)$ 1は構造体の配列です。上記の場合、strictにはid、first_name、last_nameがプロパティとして含まれます。
Reshma Suresh

26

はい、できます:

UPDATE foobar SET column_a = CASE
   WHEN column_b = '123' THEN 1
   WHEN column_b = '345' THEN 2
END
WHERE column_b IN ('123','345')

そして実用的な証明:http : //sqlfiddle.com/#!2 / 97c7ea/1


8
これは間違っています...でなくて'123'も、すべての行を更新します'345'。使用する必要がありますWHERE column_b IN ('123','456')...
MatheusOl

1
私はそうなる'456'と思います'345'
Roman Pekar

2
ELSE column_b最後のWHEN ? THEN ?行の後に追加すると、列はその現在の値に設定され、MatheusQIが言ったことを防ぐことができます。
Kevin Orriss 2013年

1
それは、彼がCOL Bに基づいて、セットコルA、複数のcolsを更新する必要がない。..を求めたものではないのです
Amalgovinus

それは正確にOPが求めたものではありませんか?column_bの値に基づいてcolumn_aだけが更新を必要とし、複数の列は必要ありません。
ケブラー

3

同様のシナリオに出くわし、CASE式は私にとって役に立ちました。

UPDATE reports SET is_default = 
case 
 when report_id = 123 then true
 when report_id != 123 then false
end
WHERE account_id = 321;

レポート-ここにあるテーブルです。account_idは上記のreport_idsと同じです。上記のクエリは、1つのレコード(条件に一致するレコード)をtrueに設定し、一致しないすべてのレコードをfalseに設定します。


2

単一のクエリで複数のを更新するには、これを試すことができます

UPDATE table_name
SET 
column_1 = CASE WHEN any_column = value and any_column = value THEN column_1_value end,
column_2 = CASE WHEN any_column = value and any_column = value THEN column_2_value end,
column_3 = CASE WHEN any_column = value and any_column = value THEN column_3_value end,
.
.
.
column_n = CASE WHEN any_column = value and any_column = value THEN column_n_value end

追加の条件が必要ない場合andは、このクエリの一部を削除してください


0

IDの配列とステータスの同等の配列があるとしましょう-これは、配列の静的SQL(値が異なるために変化しないSQLクエリ)でこれを行う方法の例です。

drop table if exists results_dummy;
create table results_dummy (id int, status text, created_at timestamp default now(), updated_at timestamp default now());
-- populate table with dummy rows
insert into results_dummy
(id, status)
select unnest(array[1,2,3,4,5]::int[]) as id, unnest(array['a','b','c','d','e']::text[]) as status;

select * from results_dummy;

-- THE update of multiple rows with/by different values
update results_dummy as rd
set    status=new.status, updated_at=now()
from (select unnest(array[1,2,5]::int[]) as id,unnest(array['a`','b`','e`']::text[]) as status) as new
where rd.id=new.id;

select * from results_dummy;

-- in code using **IDs** as first bind variable and **statuses** as the second bind variable:
update results_dummy as rd
set    status=new.status, updated_at=now()
from (select unnest(:1::int[]) as id,unnest(:2::text[]) as status) as new
where rd.id=new.id;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.