GaussDB SQL基础语法示例:循环语句详解

GaussDB SQL基础语法示例:循环语句详解
循环是数据库编程中实现迭代操作的核心工具,GaussDB基于PL/pgSQL支持多种循环结构。本文通过真实业务场景,系统讲解循环的语法形式、应用场景及优化技巧。

一、基础循环结构

  1. LOOP基础循环
DO $$
DECLARE
    counter INT := 0;
BEGIN
    LOOP
        counter := counter + 1;
        RAISE NOTICE '当前值:%', counter;
        EXIT WHEN counter >= 5; -- 执行5次后退出
    END LOOP;
END 
$$;
  1. WHILE条件循环
DO $$
DECLARE
    i INT := 10;
BEGIN
    WHILE i > 0 LOOP
        RAISE NOTICE '倒计时:%', i;
        i := i - 1;
    END LOOP;
END 
$$;
  1. FOR范围循环
DO $$
BEGIN
    FOR num IN 1..5 LOOP
        RAISE NOTICE '循环计数:%', num;
    END LOOP;
    
    -- 反向循环
    FOR num IN REVERSE 1..5 LOOP
        RAISE NOTICE '逆序计数:%', num;
    END LOOP;
END 
$$;

二、游标循环处理

  1. 显式游标循环
DO $$
DECLARE
    cur SYS_REFCURSOR;
    emp_id INT;
    emp_name VARCHAR;
BEGIN
    OPEN cur FOR SELECT id, name FROM employees;
    LOOP
        FETCH cur INTO emp_id, emp_name;
        EXIT WHEN cur%NOTFOUND;
        RAISE NOTICE '员工:%,ID:%', emp_name, emp_id;
    END LOOP;
    CLOSE cur;
END 
$$;
  1. FOR游标自动循环
DO $$
DECLARE
    cur REFCURSOR;
    dept_record RECORD;
BEGIN
    cur := 'SELECT * FROM departments'::REFCURSOR;
    LOOP
        FETCH cur INTO dept_record;
        EXIT WHEN cur%NOTFOUND;
        RAISE NOTICE '部门:% (人数:%)', 
            dept_record.dept_name, 
            dept_record.employee_count;
    END LOOP;
END 
$$;

三、高级应用场景

  1. 批量数据操作
CREATE OR REPLACE PROCEDURE batch_update_salary()
LANGUAGE plpgsql AS $$
DECLARE
    emp_rec RECORD;
BEGIN
    FOR emp_rec IN 
        SELECT id, salary FROM employees WHERE dept = 'IT'
    LOOP
        UPDATE employees 
        SET salary = salary * 1.1 
        WHERE CURRENT OF emp_rec; -- 使用游标当前记录
    END LOOP;
END;
$$;

-- 调用存储过程
CALL batch_update_salary();
  1. 动态SQL循环
DO $$
DECLARE
    sql_query TEXT;
    table_name TEXT := 'sales';
BEGIN
    sql_query := format('SELECT * FROM %I', table_name);
    EXECUTE sql_query;
    
    -- 循环处理动态结果
    FOR i IN 1..10 LOOP
        RAISE NOTICE '动态循环执行第%次', i;
    END LOOP;
END 
$$;

四、性能优化技巧

  1. 批量处理代替逐行循环
-- 优化前(逐行处理)
DO $$
DECLARE
    rec RECORD;
BEGIN
    FOR rec IN SELECT * FROM large_table LOOP
        INSERT INTO temp_table VALUES (rec.*);
    END LOOP;
END 
$$;

-- 优化后(批量操作)
INSERT INTO temp_table 
SELECT * FROM large_table; -- 单次操作提升性能
  1. 游标缓存优化
-- 使用WITH HOLD游标保持结果集
BEGIN
    DECLARE cur SCROLL CURSOR WITH HOLD FOR 
        SELECT * FROM orders;
    -- 后续循环处理...
END;

五、关键注意事项

​​循环控制​​

-- 错误示例:缺少EXIT导致无限循环
DO $$
DECLARE 
    i INT := 0;
BEGIN
    LOOP
        i := i + 1;
        RAISE NOTICE '值:%', i;
        -- 缺少EXIT条件将永久循环
    END LOOP;
END 
```2. ​**​作用域管理​**​```sql -- 错误示例:嵌套块变量覆盖 DO $$ DECLARE counter INT := 10; BEGIN DO
   DECLARE 
       counter INT := 20; -- 内层变量遮蔽外层
   BEGIN
       RAISE NOTICE '内层值:%', counter;
   END $$;
   RAISE NOTICE '外层值:%', counter; -- 仍输出10
END $$;
  1. 资源释放
-- 必须显式关闭游标
DO $$
DECLARE
    cur REFCURSOR;
BEGIN
    OPEN cur FOR SELECT * FROM employees;
    -- ...处理数据...
    CLOSE cur; -- 防止资源泄漏
END 
$$;
六、典型错误案例
-- 错误1:未处理NULL值
DO $$
DECLARE 
    result INT;
BEGIN
    SELECT salary INTO result FROM employees WHERE id=999; -- 无记录返回
    RAISE NOTICE '薪资:%', result; -- 输出NULL
END 
$$;

-- 正确做法:添加NULL判断
DO $$
DECLARE 
    result INT;
BEGIN
    SELECT salary INTO result FROM employees WHERE id=999;
    IF FOUND THEN
        RAISE NOTICE '薪资:%', result;
    ELSE
        RAISE NOTICE '记录不存在';
    END IF;
END 
$$;

-- 错误2:类型不匹配
DO $$
DECLARE 
    num_str TEXT := '123A';
BEGIN
    num_str := num_str::INT; -- 转换失败抛出异常
END 
$$;

-- 正确写法:使用安全转换
DO $$
DECLARE 
    num_str TEXT := '123A';
    num_num INT;
BEGIN
    BEGIN
        num_num := num_str::INT;
    EXCEPTION WHEN others THEN
        num_num := 0;
    END;
END 
$$;
七、实战技巧
​​分页查询实现​​
DO $$
DECLARE
    page_size INT := 100;
    current_page INT := 3;
    offset_value INT;
BEGIN
    offset_value := (current_page-1)*page_size;
    FOR rec IN 
        SELECT * FROM large_table 
        ORDER BY id 
        LIMIT page_size OFFSET offset_value
    LOOP
        -- 处理每页数据
    END LOOP;
END 
$$;
​​树形结构遍历​​
WITH RECURSIVE category_tree AS (
    SELECT id, parent_id, name 
    FROM categories 
    WHERE parent_id IS NULL
    UNION ALL
    SELECT c.id, c.parent_id, c.name
    FROM categories c
    JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree;
通过合理运用循环语句,可以实现复杂的数据处理逻辑。建议结合GaussDB的EXPLAIN ANALYZE工具分析循环性能,对大批量数据处理优先考虑基于集合的操作替代逐行循环。更多高级用法可参考《GaussDB PL/pgSQL编程指南》。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值