PostgreSQL では、PL/pgSQL という手続き言語を使うことができる。標準の SQL にはないループ文などを書くことができるため、試しに FOR 文を動かしてみる。
サンプルデータ
過去の記事でも利用している、都道府県コード(id)とローマ字表記(name)のテーブルで試してみる。
postgres=# SELECT * FROM prefecture ORDER BY id LIMIT 10; id | name ----+----------- 1 | Hokkaido 2 | Aomori 3 | Iwate 4 | Miyagi 5 | Akita 6 | Yamagata 7 | Fukushima 8 | Ibaraki 9 | Tochigi 10 | Gunma (10 rows)
動かしてみたコード
例えば、サンプルデータのテーブルから id と name を SELECT し、1行ずつ出力するようなスクリプトは以下のようになる。
DO $$ DECLARE rec RECORD; BEGIN FOR rec IN SELECT id, name FROM prefecture LOOP RAISE NOTICE '%, %', rec.id, rec.name; END LOOP; END; $$ LANGUAGE plpgsql;
DECLARE rec RECORD
はいわゆる変数宣言の部分で、こちらで宣言した変数 rec に SELECT 文の結果が入るようになる。
また、RAISE NOTICE
はターミナルにメッセージを出力する部分で、'%' の部分は指定したパラメータで順に置き換わって出力される。
出力は以下のようになる。
NOTICE: 1, Hokkaido NOTICE: 2, Aomori NOTICE: 3, Iwate ( ... 中略 ... ) NOTICE: 45, Miyazaki NOTICE: 46, Kagoshima NOTICE: 47, Okinawa
他にも、[1-10] のようなリストを作成して id を指定するような FOR ループを回すこともできる。
DO $$ DECLARE rec RECORD; BEGIN FOR counter IN 1..10 LOOP SELECT * INTO rec FROM prefecture WHERE id = counter; RAISE NOTICE '%', rec.name; END LOOP; END; $$ LANGUAGE plpgsql;
注意点として、SELECT 結果を RECORD に入れるなど他の場所で利用せずに実行しようとした場合はエラーとなり実行が失敗する。
postgres=# DO $$ BEGIN FOR counter IN 1..10 LOOP SELECT * FROM prefecture WHERE id = counter; END LOOP; END; $$ LANGUAGE plpgsql; ERROR: query has no destination for result data HINT: If you want to discard the results of a SELECT, use PERFORM instead. CONTEXT: PL/pgSQL function inline_code_block line 5 at SQL statement
SELECT だけしたい場合は PERFORM を利用する必要があるということではあるが、出力や他の箇所での利用もしないのであれば実行しても何も起きないのと同義なので、エラーが出た場合は処理内容を見直して修正するのが良さそうである。
参考サイト
PL/pgSQL では FOR 以外にも色々な制御文が使える。ドキュメントにもサンプルコードが載っているため参考になる。
- 公式ドキュメント( PostgreSQL 15.4 文書: 第43章 PL/pgSQL — SQL手続き言語 )