本題に入る前に、みんながよくハマるミスや抜けをちょっと見てみよう。SQLのミスって、エンジニアなら誰でも痛い思いしたことあるよね。しかも、だいたい一番困るタイミングで起きるんだよな。
1. シンタックスエラー: 「IFの閉じ忘れ」
シンタックスエラーは一番基本的な問題だけど、思ったよりよく出る。たとえば、IFの条件ブロックをEND IF;で閉じるのを忘れると、コンパイラにすぐ怒られる。
ミスの例:
CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
IF num > 0 THEN
RETURN 'ポジティブ';
ELSE
RETURN 'ネガティブ';
-- どこかでEND IF;が消えた
END;
$$ LANGUAGE plpgsql;
このコードを実行しようとすると、ERROR: syntax error at or near "END"ってエラーが出る。なぜかというと、IFブロックが閉じられてないから。
こういうミスを防ぐには?
いつもコードの構造を意識しよう。ブロック(たとえばIF)を開いたら、すぐに閉じるのも書いておくといい。修正版はこんな感じ:
CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
IF num > 0 THEN
RETURN 'ポジティブ';
ELSE
RETURN 'ネガティブ';
END IF; -- ブロックを閉じるのを忘れずに
END;
$$ LANGUAGE plpgsql;
2. CASEで全条件の処理忘れ: 「どこにも当てはまらなかったら?」
CASEを使うときは、予想外の値が来たときのためにELSEブランチも必ず書こう。これがないと、NULLが返ってきて困ることになる。
ミスの例:
CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
RETURN CASE grade
WHEN 'A' THEN 'エクセレント'
WHEN 'B' THEN 'グッド'
WHEN 'C' THEN 'アベレージ'
-- もしgrade = 'D'や他の評価だったら?
END;
END;
$$ LANGUAGE plpgsql;
Dを渡すと、この関数はNULLを返しちゃう。これが原因でバグることもある。
修正版:
CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
RETURN CASE grade
WHEN 'A' THEN 'エクセレント'
WHEN 'B' THEN 'グッド'
WHEN 'C' THEN 'アベレージ'
ELSE '不明な評価' -- 他のケースもキャッチ
END;
END;
$$ LANGUAGE plpgsql;
3. 無限ループの問題: 「なんでサーバーが固まったの?」
LOOPを使うとき、抜ける条件を忘れがち。これで無限ループになっちゃう:
ミスの例:
CREATE OR REPLACE FUNCTION infinite_loop_demo()
RETURNS VOID AS $$
DECLARE
i INTEGER := 1;
BEGIN
LOOP
i := i + 1;
-- 抜ける条件がない!
END LOOP;
END;
$$ LANGUAGE plpgsql;
このコードはサーバーを固めちゃう。ループが永遠に終わらないから。
修正方法:
EXITで抜ける条件を追加しよう:
CREATE OR REPLACE FUNCTION finite_loop_demo()
RETURNS VOID AS $$
DECLARE
i INTEGER := 1;
BEGIN
LOOP
i := i + 1;
IF i > 10 THEN
EXIT; -- 抜ける条件
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
4. ループでのイテレーション抜け漏れ: 「足りないデータはどうなる?」
CONTINUEでイテレーションをスキップするとき、全部のパターンをちゃんと考えてないとミスることがある。たとえば:
ミスの例:
CREATE OR REPLACE FUNCTION skip_even()
RETURNS VOID AS $$
DECLARE
i INTEGER := 0;
BEGIN
WHILE i < 10 LOOP
i := i + 1;
IF i % 2 = 0 THEN
CONTINUE; -- 偶数はスキップ
END IF;
RAISE NOTICE '奇数: %', i;
END LOOP;
END;
$$ LANGUAGE plpgsql;
もし全部の数字が偶数だったら?サーバーは動くけど、何も表示されない。
修正方法:
全部のデータをちゃんと処理してるか確認して、ログも追加しよう:
CREATE OR REPLACE FUNCTION skip_even_logging()
RETURNS VOID AS $$
DECLARE
i INTEGER := 0;
BEGIN
WHILE i < 10 LOOP
i := i + 1;
IF i % 2 = 0 THEN
RAISE NOTICE '偶数スキップ: %', i;
CONTINUE;
END IF;
RAISE NOTICE '奇数: %', i;
END LOOP;
END;
$$ LANGUAGE plpgsql;
これで、どの数字がスキップされたかも見えるようになる。
5. エラー処理のミス: 「RAISE EXCEPTIONどこいった?」
RAISE EXCEPTIONでエラー処理するのは強力だけど、使い方を間違えるとすぐバグる。
ミスの例:
CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
IF num < 0 THEN
RAISE '負の数はダメだよ!';
END IF;
RETURN num * num;
END;
$$ LANGUAGE plpgsql;
このコードはエラーになる。なぜならRAISEのシンタックスが間違ってる(レベル指定がない)。
修正版:
CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
IF num < 0 THEN
RAISE EXCEPTION '負の数はダメだよ!';
END IF;
RETURN num * num;
END;
$$ LANGUAGE plpgsql;
6. ロギングのミス: 「なんでerror_logにエラーが書き込まれないの?」
error_logテーブルへの書き込みがうまくいかないのは、INSERT INTOのクエリミスが原因かも。
ミスの例:
CREATE OR REPLACE FUNCTION log_error(err_msg TEXT)
RETURNS VOID AS $$
BEGIN
INSERT INTO error_log (error_message, error_time)
VALUES (err_msg, CURRENT_TIMESTAMP); -- カラム名が違ったら?
END;
$$ LANGUAGE plpgsql;
もしerror_logテーブルのカラム名が(たとえばerror_msgに)変わってたら、これでエラーになる。
防ぐには:
テーブル構造をちゃんと確認するか、スキーマをしっかり管理しよう。
7. うっかりミスと「ヒューマンエラー」
ミスは技術的なものだけじゃなくて、うっかりや注意不足でも起きる。デバッグの消し忘れ、使ってない変数、コードのフォーマット崩れ…こういうのがあると、関数がカオスになる。
例:
DECLARE
i INTEGER; -- 使わない変数、なんであるの?
修正:いらないコードは消して、スッキリ分かりやすくしよう。
これでPL/pgSQLでよくあるミスを避けて、もっと楽しくバグの少ないコードが書けるはず!テスト・ロギング・バグ修正は早めにやって、余計なストレスやクライアントからの電話を減らそう!
GO TO FULL VERSION