ネストされたループっていうのは、他のループの中で動くループのことだよ。面接の質問コーナーを想像してみて、1つの質問からさらに細かい質問が出てくる感じ。ネストされたループのロジックはこう:外側のループがイテレーションして、そのたびに内側のループが回るんだ。
例:掛け算表
1から5までの数字の掛け算表を作る関数を書いてみよう。これはネストされたループの超定番例だね:
CREATE OR REPLACE FUNCTION generate_multiplication_table()
RETURNS VOID AS $$
BEGIN
FOR i IN 1..5 LOOP -- 外側のループ
FOR j IN 1..5 LOOP -- 内側のループ
RAISE NOTICE '% x % = %', i, j, i * j; -- 結果をログに出す
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- 関数の呼び出し:
SELECT generate_multiplication_table();
動きのロジック:
- 外側のループが
iに1から5までの値を渡す。 - それぞれの
iについて、内側のループがjに1から5までの値を渡す。 - 毎回
iとjを組み合わせて掛け算の結果を計算する。 - 出力はミニ掛け算表みたいになる:
1 x 1 = 1
1 x 2 = 2
...
5 x 5 = 25
実践:2つのテーブルの共通部分を探す
じゃあ、もうちょっと「リアル」な例を作ってみよう。例えば、2つのテーブルがあるとする:
students(学生、名前が入ってる)courses(彼らが登録してるコース)
複数のコースに登録してる学生を探したい。ネストされたループを使ってみよう:
CREATE OR REPLACE FUNCTION find_students_with_multiple_courses()
RETURNS TABLE(student_name TEXT, course_name TEXT) AS $$
BEGIN
FOR student IN SELECT DISTINCT student_name FROM students LOOP
FOR course IN SELECT DISTINCT course_name FROM courses WHERE student_id = student.student_id LOOP
RETURN QUERY SELECT student.student_name, course.course_name;
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- 関数の呼び出し:
SELECT * FROM find_students_with_multiple_courses();
再帰
再帰っていうのは、関数が自分自身を呼び出すことだよ。SQLを説明してって友達に頼んだら、「このレクチャーを読んで」って言われて、そのレクチャーがまた自分に戻ってくる感じ… 再帰と無限ループは違うから注意してね。再帰には必ず「止める条件」(もう自分を呼ばないポイント)があるんだ。
例:数値の階乗を計算する
数値nの階乗は、1からnまで全部掛けたもの。例えば5の階乗(5!)は5 * 4 * 3 * 2 * 1 = 120だよ。これを再帰で実装してみよう:
CREATE OR REPLACE FUNCTION calculate_factorial(n INTEGER)
RETURNS INTEGER AS $$
BEGIN
-- 止める条件:0か1の階乗は1
IF n = 0 OR n = 1 THEN
RETURN 1;
END IF;
-- 関数の再帰呼び出し
RETURN n * calculate_factorial(n - 1);
END;
$$ LANGUAGE plpgsql;
-- 関数の呼び出し:
SELECT calculate_factorial(5); -- 結果: 120
動きのロジック:
nが0か1なら、1を返す。n > 1なら、関数はn - 1を引数にして自分自身を呼び出し、その値にnを掛ける。- こうやって呼び出しが「積み重なって」、最後に一気に計算される。
実践例:フィボナッチ数列
フィボナッチ数列は、各数字が前の2つの数字の合計になってるやつ。最初は0, 1, 1, 2, 3, 5, 8...って続くよ。
n番目の数字を計算する関数を書いてみよう:
CREATE OR REPLACE FUNCTION fibonacci(n INTEGER)
RETURNS INTEGER AS $$
BEGIN
-- 止める条件:最初の2つの数字は決まってる
IF n = 0 THEN
RETURN 0;
ELSIF n = 1 THEN
RETURN 1;
END IF;
-- 関数の再帰呼び出し
RETURN fibonacci(n - 1) + fibonacci(n - 2);
END;
$$ LANGUAGE plpgsql;
-- 関数の呼び出し:
SELECT fibonacci(6); -- 結果: 8
いつネストされたループや再帰を使う?
ネストされたループはテーブル操作に向いてる:
- 2つのテーブル間で値を比較したいとき。
- 複雑なデータの組み合わせを作りたいとき。
再帰はこんな時に便利:
- 数列の計算(階乗やフィボナッチなど)。
- 階層構造の処理(例えば商品カテゴリのツリー)。
よくあるミス
ネストされたループは、特に大きなテーブルを扱うときは「重い」処理になりがち。普通のSQLでできないときだけ使うようにしよう。
再帰を使うときは、ちゃんと「止める条件」があるか確認してね。ないと無限に関数が呼ばれて、たぶんスタックオーバーフローのエラーになるよ。
複雑なネスト構造はデバッグが大変。RAISE NOTICEで途中経過を出力して自分を助けてあげよう。
GO TO FULL VERSION