この記事は Hello World あたたたた Advent Calendar 2025 の記事です.
今日は PostgreSQL (PL/pgSQL) で Hello World あたたたた を実装して解説していきます.
そもそも「Hello World あたたたた」が何かは 1日目の記事 をご覧ください.
実装コード
PostgreSQL には標準で PL/pgSQL (Procedural Language/PostgreSQL) という手続き型拡張言語が組み込まれており,これを使うことで SQL の中に変数や条件分岐,ループ処理などのプログラミング構造を記述できます.
今回は,関数を永続化せずにその場で実行できる DO ブロック を使用しました.
OneCompile (PostgreSQL環境) で実際に動かしてみることができます.
DO $$
DECLARE
hako text := '';
c text;
running boolean := true;
BEGIN
WHILE running LOOP
IF random() < 0.5 THEN
c := 'あ';
ELSE
c := 'た';
END IF;
RAISE NOTICE '%', c;
hako := hako || c;
IF right(hako, 5) = 'あたたたた' THEN
RAISE NOTICE '--------------------';
RAISE NOTICE '%', hako;
RAISE NOTICE 'お前はもう死んでいる';
running := false;
END IF;
END LOOP;
END $$;
実行結果
上記のコードを psql などのクライアントで実行すると,以下のように出力されます.
NOTICE: あ
NOTICE: た
NOTICE: あ
... (中略) ...
NOTICE: た
NOTICE: --------------------
NOTICE: あたあたあたたたた
NOTICE: お前はもう死んでいる
DO
このように,1文字ごとに NOTICE: という接頭辞がつき,必ず改行されて表示されます.(なぜこうなるのかは後述します)
実行方法
Python や Bash と異なり,データベース言語である PostgreSQL は実行手順がやや特殊です.環境に応じて 2 つの方法を紹介します.
1. ローカルの PostgreSQL で実行する場合
PC に PostgreSQL がインストールされている場合の手順です.
- 上記のコードを
main.sqlという名前で保存します. - ターミナルで以下のコマンドを実行します.
psql -f main.sql
# 接続エラーが出る場合は接続先DBを指定
# psql -d postgres -f main.sql
2. Docker で実行する場合(環境構築不要)
手元に PostgreSQL がない場合でも,Docker を使えば一時的なコンテナを立てて実行できます.
DB サーバーの起動を待つ必要があるため,2 段階で実行します.
# 1. サーバーをバックグラウンドで起動
docker run --name pg-atatata -e POSTGRES_PASSWORD=password -d postgres
# 2. スクリプトを流し込む
docker exec -i pg-atatata psql -U postgres < main.sql
# 3. 終わったらコンテナを削除
docker rm -f pg-atatata
コードと文法の解説
無名コードブロックと変数宣言
DO $$
DECLARE
hako text := '';
c text;
running boolean := true;
BEGIN
...
END $$;
DO は,関数を定義せずにその場で PL/pgSQL のコードを実行するための構文です.
コード全体は $$ ... $$ で囲まれていますが,これは ドルクォート構文 と呼ばれる PostgreSQL 独自の文字列表記で,シングルクォート内のエスケープを気にせずに長いコードを書けるという利点があります.
DECLARE ブロックでは変数を宣言します.PostgreSQL は静的型付け言語であり,すべての変数に明示的な型指定が必要です.
-
text: 可変長文字列型 -
boolean: 真偽値型
また,変数への代入には Pascal 系言語に由来する := 演算子を使用します.
これは比較演算子の = と役割を明確に分けるためです.
なお,変数名を c としているのは,char や character といった SQL の型名と意味的に紛らわしくなるのを避けるためです.
WHILE 文によるループ
WHILE running LOOP
-- 処理内容
END LOOP;
WHILE 文は,条件式が true の間,LOOP から END LOOP までのブロックを繰り返します.
PL/pgSQL の制御構文は,IF ... END IF や LOOP ... END LOOP のように,明示的なキーワードでブロックを閉じる形式になっています.
これは Ada や Oracle PL/SQL の影響を強く受けた設計です.
乱数生成と条件分岐
IF random() < 0.5 THEN
c := 'あ';
ELSE
c := 'た';
END IF;
PostgreSQL の組み込み関数 random() は,0.0 以上 1.0 未満の倍精度浮動小数点数を返します.
今回は「あ」と「た」を等確率(50%)で選びたいので,0.5 を閾値として条件分岐しています.
出力と文字列結合
RAISE NOTICE '%', c;
hako := hako || c;
ここが PostgreSQL 独特のポイントです.
-
出力(
RAISE NOTICE)
PostgreSQL には,プログラミング言語におけるprintのような標準出力機能はありません.
代わりにRAISE NOTICEを用いて,クライアントへ「通知メッセージ」を送信します.
%はプレースホルダーで,C 言語のprintfと同様に後続の引数で置換されます. -
文字列結合(
||)
文字列の結合には||(ダブルパイプ)演算子を使用します.
これは SQL 標準で定められた正式な書き方です.
SQL において+は数値演算を意味するため,文字列に対して使用するとエラーになるか,暗黙の型変換が試みられて失敗します.
終了判定
IF right(hako, 5) = 'あたたたた' THEN
...
running := false;
END IF;
hako の末尾 5 文字が「あたたたた」になったかどうかを判定しています.
-
right(str, n): 文字列の右側(末尾)から n 文字を取得する関数 - 文字列比較には
=を使用
条件を満たした場合,running フラグを false に更新することで,次回の WHILE 判定時にループを抜けます.
なぜ出力が改行されてしまうのか?
実行結果を見ると,以下のように 1 文字ずつ改行されて出力されています.
NOTICE: あ
NOTICE: た
...
Python の print('あ', end='') や Bash の echo -n 'あ' のように,「改行せずに標準出力へ書き込む」機能は PostgreSQL には存在しません.
RAISE NOTICE は画面表示用の命令ではなく,あくまで 「クライアントへ通知メッセージを送る」 ための仕組みです.
1 回の RAISE は 1 つのメッセージとして送信され,多くのクライアント(psql など)ではそれを 1 行のログとして表示します.
そのため,文字を連続して出力するようなストリーム的な表示は実現できません.
これは PostgreSQL が「対話的な表示」を目的とした言語ではなく,「データの整合性と処理」を目的としたデータベースであることに由来します.
手続き型拡張 SQL の歴史と種類
今回使用した PL/pgSQL は,PostgreSQL に標準で組み込まれている手続き型拡張言語です.
SQL の世界には,標準 SQL とは別に,各データベース製品が独自に実装した手続き型言語が存在します.
-
PL/SQL(Oracle Database)
手続き型 SQL の先駆けであり,非常に強力な言語です.
PostgreSQL の PL/pgSQL は,この Oracle の PL/SQL を強く意識して設計されており,ブロック構造や例外処理の構文がよく似ています. -
T-SQL(Transact-SQL / SQL Server)
Microsoft SQL Server で使用される言語です.
変数宣言に@を使うなど,PL/pgSQL や PL/SQL とは異なる独自の構文体系を持っています. -
PL/pgSQL(PostgreSQL)
PostgreSQL 標準の手続き型言語です.
Oracle 互換性を意識した設計により,商用 DB からの移行が比較的容易という特徴があります.
近年の Web 開発では,ロジックの多くはアプリケーション側(Python, Ruby, Go など)に書かれることが一般的です.
しかし,トリガー処理や複雑な集計,データベース内部で完結させたいロジックにおいて,PL/pgSQL は今でも非常に強力な武器になります.
感想
普段は SELECT * FROM ... のようなクエリを ORM 経由で実行するだけになりがちな PostgreSQL ですが,その内部には PL/pgSQL というチューリング完全な手続き型言語が存在し,このようなデータベースはプログラムも実行できる計算機であるということを再認識しました.