PL/SQLとは?PostgreSQLユーザーにもわかるOracleストアド入門

SQL & DB

「PL/SQLって聞いたことあるけど、ぶっちゃけ何それ?」

私も最初はそう思ってました。

PostgreSQLしか触ったことがなかった私に突然ふってわいた“Oracleの世界”。

「SQLに“手続き型”?なにそれ、RPGのジョブチェンジ的なやつ?」と混乱しつつも、気づけばストアドと仲良くなってました。

この記事では、PostgreSQLユーザー目線で「PL/SQLってこういうものなんだ!」とすんなり入れるように、やさしく・わかりやすくご紹介します。

同じように“何それ状態”から始まるあなたに、ちょっとでも安心してもらえたら嬉しいです。

  1. はじめに 〜PostgreSQL派だった私がPL/SQLと出会った日〜
  2. PL/SQLって何?SQLとの違いと役割をざっくり理解する
    1. PL/SQLって、なに者?
    2. じゃあ、SQLとはどう違うの?
    3. 何が便利なの?
  3. PL/SQLって何?SQLとの違いと役割をざっくり理解する
    1. PL/SQLのざっくり正体
    2. SQLとどう違うの?
    3. なぜ業務でPL/SQLが使われるの?
  4. PL/pgSQLとの違いに戸惑った話(でも大丈夫!)
    1. その1:セミコロン(;)の使い方がやたらシビア
    2. その2:関数の戻り値とRETURNの扱いが違う
    3. その3:NULLの扱いがシビアすぎてハマる
    4. その他にも微妙な違いが盛りだくさん
  5. 基本構文をやってみよう!PL/SQLの書き方入門
    1. PL/SQLの基本構造
    2. Hello PL/SQL!はじめの一歩を書いてみる
    3. 制御構文もサクッと使える
      1. IF文
      2. FORループ
    4. EXCEPTIONでエラー処理もバッチリ
    5. まとめ:構文に慣れるとPL/SQLの世界がぐっと近くなる
  6. 業務で使ったストアドプロシージャのサンプル紹介
    1. シナリオ:月次請求データの自動登録処理
    2. ざっくり要件
    3. 書いてみたストアドプロシージャ(簡略版)
    4. 解説ポイント
    5. 運用に組み込んだ方法
    6. 書いてみて感じたこと
  7. PL/SQLでハマりがちなポイントとその回避法
    1. ハマりポイント①:NULLは“比較”できない!?
    2. ハマりポイント②:DBMS_OUTPUT.PUT_LINEが出ない!?
    3. ハマりポイント③:変数宣言で型を間違えて地味に詰む
    4. ハマりポイント④:コミットの場所、そこじゃない!
    5. その他よくある“つまずきポイント”
    6. まとめ:「つまずくポイント=学びの入り口」
  8. まとめ 〜PL/SQLは味方にできる!次につながる学び方〜
    1. PL/SQLを味方にする3つのステップ
    2. 次に学ぶと役立つトピック

はじめに 〜PostgreSQL派だった私がPL/SQLと出会った日〜

「PL/SQL? ……あ、それ“SQL”の仲間ですか?」

そんなふうに肩の力を抜いていたあの日の私に、そっと教えてあげたい。

君はこれから“手続き型SQL”という名の異世界に旅立つことになるよ……と。

私はこれまで、ずっとPostgreSQLを使ってきました。

ストアドプロシージャも、トリガーも、pgAdminでポチポチ書いてそれなりにやってきたつもりです。

でもある日、業務で渡されたのは「PL/SQLで作られた業務ロジックの改修依頼」。

OracleもPL/SQLも、名前は知ってるけど正直「なんかエンタープライズな世界の話でしょ?」くらいに思ってました。

でも現実は厳しくて、「実行計画が遅い原因を調査して、必要ならPL/SQLごと書き直して」と言われ……それ、いきなりラスボス戦やん。

「DECLAREって何?」「BEGINで何が始まるの?」「EXCEPTIONって、例外処理……ぽいけど、どうやるの?」

とにかく、調べて、書いて、エラーを浴びて、また書いて。

気づけば、少しずつですがPL/SQLが読める・書けるようになっていました。

この記事は、そんなふうに「PL/SQL?何それ?」から始まった私が、PostgreSQLユーザーとしてどんな風にこの言語と付き合っていけたのかをまとめたものです。

PostgreSQLとPL/pgSQLに慣れている方なら、「あ、これって○○に似てるな」と思える瞬間がたくさんあります。

そしてOracle独自のクセに「え、そこそうするの!?」と驚くことも。

この章では、私と同じように「Oracle系にはちょっと距離を感じる……でもやらなきゃ!」という方に向けて、PL/SQLの世界への第一歩をやさしくお届けします。

次の章からは、PL/SQLって何者なの?というところを、PostgreSQLとの比較を交えて解説していきますね。

PL/SQLって何?SQLとの違いと役割をざっくり理解する

正直、「SQLが書けるからPL/SQLもきっといけるでしょ」と思ってました。

ええ、思ってましたとも……最初は。

でもPL/SQLは、いわば「SQLに筋肉をつけて、ロジックを動かせるようにした」手続き型の言語なんです。

基本的なSQL(SELECT、INSERTなど)をベースにしつつ、「条件分岐したい」「ループで処理したい」「例外が起きたときに処理を分けたい」といったニーズに対応できるようになっています。

PL/SQLって、なに者?

PL/SQLとは、Oracle Databaseのために設計された手続き型言語です。

名前の通り、SQLに「Procedural(手続き型)」の要素を加えたもので、以下のようなことができます:

  • IF文やループ処理などの制御構造
  • 例外処理(エラーが起きたときの対応)
  • ストアドプロシージャやファンクションの定義と実行
  • トリガーの設定(データ変更時に自動で動く処理)

これらを使えば、データベースの中に業務ロジックを「組み込んで自動で動かす」ことができます。

つまり、「アプリケーションからデータベースを叩く」だけじゃなく、データベースそのものが“動ける存在”になるんです。ちょっとロボットみたいですね。

じゃあ、SQLとはどう違うの?

機能SQLPL/SQL
主な用途データ操作(SELECTなど)業務ロジック(IF文、ループ、例外処理など)
実行単位1文単位複数の文を1ブロックとして実行可能
条件分岐/繰り返し×
エラー処理 限定的例外ハンドラで柔軟に処理可能

PostgreSQLにもPL/pgSQLという似たような言語がありますが、文法や実行方法にちょっとした違いが多いので、最初は戸惑うかもしれません(私は戸惑いました)。

何が便利なの?

PL/SQLの便利さはズバリ、処理をまとめて書いて、データベース内で完結できること。

たとえば「毎晩22時に集計処理をして、エラーが出たら担当者にフラグを立てる」みたいな一連の処理も、PL/SQLで書けばDBが自動でやってくれるんです。

運用負荷がグッと下がる場面、多いですよ。

PL/SQLって何?SQLとの違いと役割をざっくり理解する

PL/SQLって、名前はSQLっぽいけど、ちょっと見慣れない構文が多いし、BEGINとかEXCEPTIONとか出てくるし…「つまり何者?」というのが最初の正直な感想でした。

でも、ひとことで言うと 「SQLにプログラム的な力を与えた言語」 です。

条件分岐、ループ処理、エラー処理など、「アプリ側でやってたような処理を、DBの中でやってくれるスーパーSQL」と考えるとちょっと親しみやすくなりませんか?

PL/SQLのざっくり正体

PL/SQL(Procedural Language/SQL)は、Oracle Database専用の手続き型言語です。

名前の通り、SQLに「手続き的(=処理の流れを制御する)」な仕組みを足したもので、以下のようなことができます:

  • IF文やLOOP文で処理フローを組む
  • 例外処理(EXCEPTION)でエラーに柔軟に対応
  • ストアドプロシージャやファンクションでロジックを再利用
  • トリガーでデータ変更に自動対応

これらの機能によって、「データベースがただの保管箱」から「ちょっとしたアプリケーションのようにふるまう存在」になります。

SQLとどう違うの?

PostgreSQLでもSQLでデータを操作しますが、PL/SQLはそれだけじゃ終わりません。

「SQL=命令」「PL/SQL=命令+流れ」というイメージを持つとわかりやすいかもしれません。

内容SQLPL/SQL
主な目的データ操作ロジック制御+データ操作
制御構文なしIF / LOOP / EXIT などが使える
エラー処理制限ありEXCEPTION で柔軟な対応が可能
再利用性低(毎回SQLを書く)ストアドプロシージャやファンクションとして使い回せる

たとえば、 「条件に応じてINSERTするテーブルを変えたい」とか 「ある条件でエラーが出たときだけロールバックしたい」といった処理は、SQL単体では難しいけれど、PL/SQLならサクッと書ける、という違いがあります。

なぜ業務でPL/SQLが使われるの?

単純です。便利だからです。

例えば:

  • ネットワーク越しに大量のSQLを送るより、DB内で完結させたほうが速い
  • 一連の業務ロジックをバッチ処理のように定義しておける
  • アプリの改修なしで、DB側でロジックを更新できる

特に、「Oracle+レガシーな業務ロジック」が多く残る現場では、PL/SQLの出番がバリバリあるわけですね。

PostgreSQLでもPL/pgSQLを使えば似たことはできますが、「文法や制約が微妙に違う」ため、最初は戸惑います。

でも大丈夫、慣れれば“Oracle語”にも耳が慣れてきます。

次章では、PL/pgSQLとの違いに焦点を当てて、「PostgreSQL派がひっかかりがちなポイント」をやさしく解説していきます。

構文のクセ、デフォルトの挙動、あの「セミコロン」への戸惑い……あるある話をたっぷりお届けします!

PL/pgSQLとの違いに戸惑った話(でも大丈夫!)

PostgreSQLに慣れていた私にとって、PL/SQLの世界は一見似てるけど細かいところがちがう双子の兄弟みたいな存在でした。

「え、見た目同じなのになんでここでエラーになるの?」——このセリフ、私は何度も言いました。

ここでは、私が実際に戸惑ったPL/pgSQLとの違いをピックアップして、やさしく整理してみます。

「これ知ってたらあんなに混乱しなかったのに!」というポイントばかりなので、ぜひ“あるある”を一緒に味わってください。

その1:セミコロン(;)の使い方がやたらシビア

PostgreSQLの関数を書くとき、文末のセミコロンを「まあ要るときもあるよね」くらいの感覚で使っていましたが、PL/SQLでは書き忘れると普通に怒られます。

SQL
BEGIN
  dbms_output.put_line('Hello PL/SQL') -- ← セミコロンないとエラー!
END;

文ごとにセミコロン、ブロックの終わりにEND;。

細かいけど慣れるまでは「なんで動かんの⁉」案件No.1でした。

その2:関数の戻り値とRETURNの扱いが違う

PostgreSQLではRETURNで値を返すのは比較的ゆるやかですが、PL/SQLでは関数とプロシージャの区別がはっきりしています。

  • ストアドプロシージャ → RETURNなし(副作用メイン)
  • ファンクション → 必ずRETURNが必要、戻り値の型も指定
SQL
CREATE OR REPLACE FUNCTION say_hello RETURN VARCHAR2 IS
BEGIN
  RETURN 'Hello PL/SQL!';
END;

初めて見たときは「型を指定して戻すの、やけにしっかりしてるな…」と感じました。

その3:NULLの扱いがシビアすぎてハマる

PL/pgSQLではIF val = NULL THENなんて書いても警告は出ないかもですが、PL/SQLではNULLの比較は常にFALSE扱いです。

正しくはこう:

SQL
IF val IS NULL THEN
  -- NULLのときの処理
END IF;

私はこれを知らずに「IFが効かないのなんで!?」と1時間格闘したことがあります。お恥ずかしい……。

その他にも微妙な違いが盛りだくさん

  • 文字列結合:||は共通だけど、場合によっては暗黙型変換の挙動が異なる
  • RAISE NOTICEがなく、代わりにDBMS_OUTPUT.PUT_LINE()を使う
  • トリガー作成時の制約が細かい(AFTER/BEFOREの使い方など)

PostgreSQL脳で突っ込んでいくと、「え、ここPL/SQL警察が来るやつやん…」みたいなエラーに遭遇することがあるので、ちょっとだけ“Oracleモード”にスイッチを切り替える意識が大事です。

最初は「同じように書いたつもりなのに動かない…」の連続ですが、逆に言えば、違いさえ知ってしまえば、PL/SQLも怖くない。

むしろOracleの文化をちょっと覗けて楽しくなってくるかもしれません。

次章では、そんなPL/SQLをいよいよ“手を動かして書いてみる”フェーズに進みます。

基本の構文やコードブロックを一緒に確認していきましょう!

基本構文をやってみよう!PL/SQLの書き方入門

はじめてPL/SQLを書くときの私は、まるで異国の駅前に降り立った観光客のようでした。

文字は見たことあるけど文法が通じない。助けて、BEGINって何から始まるの?

安心してください。PL/SQLの構文は一見堅そうに見えますが、基本を押さえてしまえば「あれ、そんなに怖くないかも」という気持ちに変わってきます。

まずは“これさえ押さえれば書き始められる”というベースを一緒に見ていきましょう。

PL/SQLの基本構造

PL/SQLは「ブロック構造」という考え方で書かれます。

つまり、ひとまとまりの処理をDECLARE–BEGIN–EXCEPTION–ENDという“箱”で囲って書くスタイルです。

SQL
DECLARE
  -- 変数の宣言など(任意)
BEGIN
  -- 実行したい処理
EXCEPTION
  -- エラーが起きたときの処理(任意)
END;

各パートの役割

  • DECLARE: 変数やカーソルなどを宣言するパート。なくてもOK。
  • BEGIN: メインの処理を書く場所。SQL文や制御構文を記述。
  • EXCEPTION: エラー時の処理を書く場所。書かなくても構いませんが、あると優しい。
  • END;: ブロックの終わりを示すお約束のひとこと。

PostgreSQLのDO $$ BEGIN … END $$;と似てるけど、Oracleではセミコロンの位置や命名ルールがちょっとだけ厳しめです。

Hello PL/SQL!はじめの一歩を書いてみる

SQL
BEGIN
  DBMS_OUTPUT.PUT_LINE('Hello, PL/SQL!');
END;
/
  • DBMS_OUTPUT.PUT_LINEは、PostgreSQLでいうところのRAISE NOTICEのような標準出力。
  • 最後のスラッシュ/は、SQLPlusやSQL Developerでブロック実行を指示する記号*です(ここ、地味に見落としがちポイントです)。

制御構文もサクッと使える

IF文

SQL
DECLARE
  score NUMBER := 85;
BEGIN
  IF score >= 80 THEN
    DBMS_OUTPUT.PUT_LINE('合格!');
  ELSE
    DBMS_OUTPUT.PUT_LINE('がんばりましょう');
  END IF;
END;
/

FORループ

SQL
BEGIN
  FOR i IN 1..3 LOOP
    DBMS_OUTPUT.PUT_LINE('カウント: ' || i);
  END LOOP;
END;
/

EXCEPTIONでエラー処理もバッチリ

SQL
BEGIN
  -- 整数を0で割るとエラーが起きます
  DECLARE
    result NUMBER;
  BEGIN
    result := 100 / 0;
  EXCEPTION
    WHEN ZERO_DIVIDE THEN
      DBMS_OUTPUT.PUT_LINE('ゼロ除算が発生しました');
  END;
END;
/

PL/SQLではWHEN エラータイプ THENの形で例外処理を書くことができます。

ここもPostgreSQLとは違って命名規則が明確ですね。

まとめ:構文に慣れるとPL/SQLの世界がぐっと近くなる

最初は「なんか固そうな言語…」と身構えていたPL/SQLですが、書いてみると意外と親しみやすいというのが本音です。

むしろ、SQLだけでは表現しにくかった業務ロジックがぐっと書きやすくなります。

次章では、私が実際に業務で書いたPL/SQLのサンプルを紹介します。

「あのとき苦労したあの処理がこう書けたのか!」という実感を一緒に味わってもらえたらうれしいです。

業務で使ったストアドプロシージャのサンプル紹介

PL/SQLを勉強して基本構文は理解できたけど、「で、実際どんな場面で使うの?」となった方。

安心してください、私もそこが一番モヤっとしてました。

この章では、私が実際に業務で使った似たロジックを持つストアドプロシージャを紹介しながら、「PL/SQLが現場でどう使われてるのか?」のイメージをつかんでいただければと思います。

シナリオ:月次請求データの自動登録処理

案件は、ある業務システムの月次バッチ。

営業部門が入力したデータをもとに、請求テーブルにデータを自動登録する処理です。

手動対応が多くて「この作業、忘れたら怒られるんですよね…」という空気感が漂っていたので、「あ、これPL/SQLで自動化すればいいのでは」となりました。

ざっくり要件

  • 処理対象は月次テーブルにある“未請求”の取引情報
  • 顧客ID・金額・税率などをもとに、請求テーブルにINSERT
  • 既に請求済みのデータはスキップ
  • エラー時はロールバックしてログを出す

書いてみたストアドプロシージャ(簡略版)

SQL
CREATE OR REPLACE PROCEDURE generate_invoice_data IS
BEGIN
  FOR rec IN (
    SELECT id, customer_id, amount, tax_rate
    FROM transactions
    WHERE billed_flag = 'N'
  ) LOOP
    BEGIN
      INSERT INTO invoices (
        customer_id, amount, tax, created_at
      ) VALUES (
        rec.customer_id,
        rec.amount,
        rec.amount * rec.tax_rate,
        SYSDATE
      );

      UPDATE transactions
      SET billed_flag = 'Y'
      WHERE id = rec.id;

    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('処理中にエラーが発生しました: ' || SQLERRM);
        ROLLBACK;
    END;
  END LOOP;
END;
/

解説ポイント

  • FORループ+カーソルで対象レコードを1件ずつ処理
  • ネストされたBEGIN~ENDで個別トランザクション制御
  • EXCEPTIONセクションでエラー発生時の出力&ROLLBACK
  • 税込金額の計算も簡潔に済ませていてスマート!

PostgreSQLでも似たような処理は書けますが、PL/SQLならOracleに最適化された方法で堅牢なバッチ処理が組めます。

運用に組み込んだ方法

  • 夜間バッチで毎晩1回自動実行(DBスケジューラを使用)
  • 開発段階でDBMS_OUTPUT.PUT_LINEを使ってログ確認
  • 本番環境では例外時に専用ログテーブルにINSERTして通知

書いてみて感じたこと

最初は「こんなロジック、何でアプリじゃなくてDB側でやるんだろう?」と思ってましたが、書いてみて実感。

ストアド化することで“忘れない・間違えない・速い”処理が作れるんです。

Oracleの文化にちょっと戸惑いつつも、「あ、これって仕事のミスを減らすために用意されてたんだな」という気づきがあって、ちょっとPL/SQLが好きになりました。

次章では、そんな中で「ここでハマった…」という具体的なポイントや、PL/SQL特有の落とし穴についても正直にシェアしていきます。

PL/SQLでハマりがちなポイントとその回避法

PL/SQLは便利。でも、慣れないうちは「え、なにこのエラー…?」と壁にぶつかることも少なくありません。

実際、私も何度か脳内で机をひっくり返しかけました。

この章では、私が実際にハマったPL/SQLの“落とし穴”を振り返りながら、「どう回避すればよかったのか」をやさしく解説します。

PostgreSQL経験者こそ陥りやすいワナもあるので、ぜひ“予習”がてらチェックしてみてください。

ハマりポイント①:NULLは“比較”できない!?

PL/pgSQLでは書けていた IF val = NULL THEN という構文、PL/SQLでは常にFALSEになるってご存知でしたか?

SQL
IF val = NULL THEN -- ← これは永遠にTRUEにならない!

PL/SQLでは、NULLとの比較には IS NULL / IS NOT NULL を使うのが正解です。

SQL
IF val IS NULL THEN
  DBMS_OUTPUT.PUT_LINE('値がNULLです');
END IF;

回避法:NULLチェックは必ず IS NULL を使う。= や != は効かない!

ハマりポイント②:DBMS_OUTPUT.PUT_LINEが出ない!?

「ログ出力してるはずなのに、何も表示されないんですが…」という現象。

原因は単純で、DBMS_OUTPUTを有効化していないことがほとんどです。

  • SQL*Plusなら:SET SERVEROUTPUT ON
  • SQL Developerなら:[出力ペインでONにする必要あり]

回避法:「出力が出ない=エラー」ではない!環境設定をまず確認する。

ハマりポイント③:変数宣言で型を間違えて地味に詰む

PL/pgSQLでは := で型を推論してくれたりしますが、PL/SQLでは型の指定がマストな場面が多いです。

SQL
DECLARE
  username VARCHAR2 := 'Taro'; -- ← OK
  age NUMBER := '20';         -- ← これはNG(型が合わない!)

型エラーは実行前に検出されないこともあるため、事前にきっちり型確認しておくのが安心です。

回避法:「とりあえず文字列でいいか」は危険。明示的に必要な型を確認してから宣言。

ハマりポイント④:コミットの場所、そこじゃない!

PL/SQLのプロシージャは、基本的に“明示的なCOMMIT”が必要です。

PostgreSQLの感覚で「書けば自動で反映される」と思ってると、変更が反映されない!?という事態に。

SQL
BEGIN
  INSERT INTO logs (message) VALUES ('hello');
  -- COMMITしないとセッション終了時にロールバックされる
END;

ただし、トリガーの中や制約のある場所で COMMIT すると例外が発生するので要注意。

回避法:「COMMITの場所とタイミングは計画的に!」 > – トリガー中はNG > – 一括処理では最後にまとめて行う方が安全

その他よくある“つまずきポイント”

  • SQL文の末尾にセミコロン ; を忘れる(PL/SQLでは必須)
  • :=(代入)と=(比較)の混同
  • NUMBERの精度指定にやたら厳しい(例:NUMBER(5,2)の「.」以下桁数超過)

まとめ:「つまずくポイント=学びの入り口」

PL/SQLでつまずいたポイントって、実は“Oracle的な考え方”に触れるチャンスでもあります。

PostgreSQLとは設計思想が少し違うけれど、違うからこそ「なぜそうなっているのか?」に気づけるんですよね。

こういう“小さなハマり”をひとつずつ越えていくことで、PL/SQLとだんだん仲良くなれていきます。

次章では、そんなPL/SQLとの付き合いを振り返りつつ、「これからどう学びを広げていけるか?」をまとめていきます!

まとめ 〜PL/SQLは味方にできる!次につながる学び方〜

最初に「PL/SQL?なにそれ怖い」と思っていたあの頃の私。

いまなら言えます。大丈夫、PL/SQLは“仕事をラクにしてくれる心強い味方”でした。

ここまで読んでくださった方はもうお気づきかもしれません。

PL/SQLって、最初は独特に見えるけれど、その本質は「複雑な処理を、わかりやすく、安全に、データベースの中で完結できるようにするツール」なんです。

PostgreSQLユーザーの視点から見ると、ちょっと文法が違ったり、Oracle独特のクセが気になったりはしますが……

それも慣れてしまえばスパイスのようなもので、むしろ「なるほど、こういう設計思想なのか」と楽しめる瞬間も出てきます。

PL/SQLを味方にする3つのステップ

  • 「動くコードを書く」ことを目標にする
     ─ 文法の正しさより「業務ロジックが動いた!」という体験が大事です。
  • 「書いて、試して、エラーを読む」ことを恐れない
     ─ PL/SQLは試行錯誤の言語です。エラーこそ最強の先生。
  • 「この処理、PL/SQLでやれるかも?」という視点を持つ
     ─ 日々の業務の中で“自動化したいフロー”を見つけると、活用の幅が広がります。

次に学ぶと役立つトピック

  • トリガーの作り方:データ変更に自動で反応する処理
  • パッケージの利用:複数の関連処理をまとめて管理できる
  • SQLLoader*や外部ファイル連携:業務バッチで役立つ外部データ取り込み
  • 性能チューニングの基本:PL/SQLの処理を遅くしないための視点
decopon
decopon

PostgreSQL派だった私が、PL/SQLという未知の世界に戸惑いながらも少しずつ歩み寄っていく中で、「これは昔の自分にも読ませたいな」と思える内容を詰め込みました。

もしかすると、あなたも今、私と同じように「PL/SQLって難しそう…」と感じているかもしれません。でも大丈夫。PL/SQLは、決して敵ではなく、あなたの業務や知識の幅を支えてくれる、心強いパートナーになってくれます。

少しずつ、エラーと仲良くなりながら、たまに笑って、たまに「やった!」と喜びながら進んでいけたら、それで十分だと思います。

コメント

タイトルとURLをコピーしました