CodeGym /课程 /SQL SELF /嵌套循环和递归

嵌套循环和递归

SQL SELF
第 51 级 , 课程 3
可用

嵌套循环就是一个循环里面再套一个循环。你可以想象成面试的时候,一个问题引出更多的追问。嵌套循环的逻辑就是:外层循环每次迭代,内层循环就会针对每次外层的迭代再跑一遍。

例子:乘法表

我们来写个函数,生成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();

运行逻辑:

  1. 外层循环拿到i从1到5的值。
  2. 每个i,内层循环拿j从1到5的值。
  3. 每一步把ij组合起来算乘法。
  4. 输出看起来像个小表格:
   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;

-- 调用函数:
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

运行逻辑:

  1. 如果n等于0或1,返回1。
  2. 如果n > 1,函数自己调用自己,参数是n - 1,然后再乘以n
  3. 这样递归会“积累”起来,最后一起算出来。

实际例子:斐波那契数列

斐波那契数列是一串数,每个数等于前两个数的和。开头是0, 1, 1, 2, 3, 5, 8...

我们来写个函数,算第n个斐波那契数:

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;

  -- 递归调用
  RETURN fibonacci(n - 1) + fibonacci(n - 2);
END;
$$ LANGUAGE plpgsql;

-- 调用函数:
SELECT fibonacci(6); -- 结果: 8

什么时候用嵌套循环和递归?

  1. 嵌套循环适合处理表:

    • 对比两张表的数据。
    • 组合复杂的数据。
  2. 递归更适合:

    • 算序列(比如阶乘、斐波那契)。
    • 处理层级结构(比如商品分类树)。

常见错误

嵌套循环有时候会很“吃性能”,尤其是表很大的时候。只有在用普通SQL搞不定的时候才用它。

用递归的时候一定要有明确的“终止条件”。不然会无限调用自己,最后爆栈报错。

复杂的嵌套结构调试起来很难。可以用RAISE NOTICE打印中间结果帮自己排查。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION