巢狀迴圈就是一個迴圈裡面再包一個迴圈。想像你在面試被問問題,然後一個問題又引出更多細節問題。巢狀迴圈的邏輯就是:外層迴圈跑一次,內層迴圈就針對外層的每一次再跑一輪。
範例:乘法表
來寫個 function,產生 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; -- Log 結果
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- 呼叫 function:
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
練習:找兩個表的交集
現在來個比較「生活化」的例子。假設我們有兩個表:
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;
-- 呼叫 function:
SELECT * FROM find_students_with_multiple_courses();
遞迴
遞迴就是 function 會自己呼叫自己。就像你問朋友 SQL 怎麼用,他叫你去看文件,結果文件又叫你看這堂課... 不要把遞迴跟無限迴圈搞混。遞迴一定有個「停止條件」(就是 function 不再呼叫自己的點)。
範例:計算階乘
一個數字 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;
-- 遞迴呼叫 function
RETURN n * calculate_factorial(n - 1);
END;
$$ LANGUAGE plpgsql;
-- 呼叫 function:
SELECT calculate_factorial(5); -- 結果:120
運作邏輯:
- 如果
n是 0 或 1,就回傳 1。 - 如果
n > 1,function 會自己呼叫自己,參數是n - 1,然後再乘上n。 - 這樣呼叫會「堆疊」起來,最後再一起算回來。
實戰範例:Fibonacci 數列
Fibonacci 數列就是每個數字都是前兩個數字的和。開頭長這樣:0, 1, 1, 2, 3, 5, 8...。
來寫個 function 算第 n 個 Fibonacci 數:
CREATE OR REPLACE FUNCTION fibonacci(n INTEGER)
RETURNS INTEGER AS $$
BEGIN
-- 停止條件:前兩個數已知
IF n = 0 THEN
RETURN 0;
ELSIF n = 1 THEN
RETURN 1;
END IF;
-- 遞迴呼叫 function
RETURN fibonacci(n - 1) + fibonacci(n - 2);
END;
$$ LANGUAGE plpgsql;
-- 呼叫 function:
SELECT fibonacci(6); -- 結果:8
什麼時候該用巢狀迴圈跟遞迴?
巢狀迴圈很適合處理表格:
- 比對兩個表的值。
- 組合複雜的資料。
遞迴比較適合:
- 算數列(像階乘、Fibonacci)。
- 處理階層結構(像商品分類樹)。
常見錯誤
巢狀迴圈有時候效能很差,尤其是資料表很大時。真的沒辦法用一般 SQL 寫再用巢狀迴圈。
用遞迴時一定要有明確的「停止條件」。不然會無限呼叫,最後 stack overflow 掛掉。
巢狀結構太複雜會很難 debug。可以多用 RAISE NOTICE 印出中間結果幫自己。
GO TO FULL VERSION