PostgreSQL 游标处理

PostgreSQL 游标处理

简单循环处理I 


此写法是先取一条数据,然后判断循环条件 



-- 清空日志表.
Test=# truncate table log_table;
TRUNCATE TABLE

Test=# select * from test_main;
 id | value
----+-------
  1 | ONE
  2 | TWO
  4 | FOUR
(3 行记录)




CREATE OR REPLACE FUNCTION TestCursor() RETURNS void AS
$$
DECLARE
  -- 定义游标.
  c_test_main CURSOR FOR
    SELECT id, value FROM test_main;
  -- 定义存储数据的变量.
  v_id    INT;
  v_value VARCHAR(10);
BEGIN
  -- 打开游标.
  OPEN c_test_main;
  -- 填充数据.
  FETCH c_test_main INTO v_id, v_value;

  -- 假如检索到了数据,才处理.
  while found loop  
    INSERT INTO log_table VALUES (v_value);
	-- 填充下一条数据.
    FETCH c_test_main INTO v_id, v_value;
  end loop; 
  
  -- 关闭游标
  CLOSE c_test_main;
END;
$$
LANGUAGE plpgsql;




Test=# select TestCursor();
 testcursor
------------

(1 行记录)


Test=# select * from log_table;
 log_text
----------
 ONE
 TWO
 FOUR
(3 行记录)



如果 SQL 语句中, 列的数量很多, 那么定义很多的变量,对应没一列。
开发、维护成本都会比较高。
这种情况下, 可以采用  表名%rowtype  的方式, 只定义一个变量来进行处理.

-- 清空日志表.
Test=# truncate table log_table;
TRUNCATE TABLE


CREATE OR REPLACE FUNCTION TestCursor() RETURNS void AS
$$
DECLARE
  -- 定义游标.
  c_test_main CURSOR FOR
    SELECT id, value FROM test_main ORDER BY id DESC;
  -- 定义存储数据的变量.
  v_main_data  test_main%ROWTYPE;

BEGIN
  -- 打开游标.
  OPEN c_test_main;
  -- 填充数据.
  FETCH c_test_main INTO v_main_data;

  -- 假如检索到了数据,才处理.
  while found loop  
    INSERT INTO log_table VALUES (v_main_data.value);
	-- 填充下一条数据.
    FETCH c_test_main INTO v_main_data;
  end loop; 
  
  -- 关闭游标
  CLOSE c_test_main;
END;
$$
LANGUAGE plpgsql;


Test=# select TestCursor();
 testcursor
------------

(1 行记录)


Test=# select * from log_table;
 log_text
----------
 FOUR
 TWO
 ONE
(3 行记录)



简单循环处理II 

此写法是先开始循环,然后取数据,然后判断条件 




-- 清空日志表.
Test=# truncate table log_table;
TRUNCATE TABLE

Test=# select * from test_main;
 id | value
----+-------
  1 | ONE
  2 | TWO
  4 | FOUR
(3 行记录)




CREATE OR REPLACE FUNCTION TestCursor2() RETURNS void AS
$$
DECLARE
  -- 定义游标.
  c_test_main CURSOR FOR
    SELECT id, value FROM test_main;
  -- 定义存储数据的变量.
  v_id    INT;
  v_value VARCHAR(10);
BEGIN
  -- 打开游标.
  OPEN c_test_main;
  
  LOOP  
    -- 填充数据.
    FETCH c_test_main INTO v_id, v_value;
    -- 假如没有检索到数据,结束循环处理
    Exit when NOT found;
	-- 游标每一行的实际操作.
    INSERT INTO log_table VALUES (v_value);
  END LOOP; 
  
  -- 关闭游标
  CLOSE c_test_main;
END;
$$
LANGUAGE plpgsql;




Test=# select TestCursor2();
 testcursor2
-------------

(1 行记录)


Test=# select * from log_table;
 log_text
----------
 ONE
 TWO
 FOUR
(3 行记录)



支持来回滚动的游标 



-- 清空日志表.
Test=# truncate table log_table;
TRUNCATE TABLE


-- 为达到测试效果, 多加几行测试数据.
INSERT INTO test_main(id, value) VALUES (11, 'ONEONE');
INSERT INTO test_main(id, value) VALUES (12, 'ONETWO');
INSERT INTO test_main(id, value) VALUES (13, 'ONETHREE');

Test=# SELECT id, value FROM test_main ORDER BY id;
 id |  value
----+----------
  1 | ONE1
  2 | TWO1
  4 | FOUR1
 11 | ONEONE
 12 | ONETWO
 13 | ONETHREE
(6 行记录)


CREATE OR REPLACE FUNCTION TestCursorScroll() RETURNS void AS
$$
DECLARE
  -- 定义游标.
  c_test_main SCROLL CURSOR FOR
    SELECT id, value FROM test_main ORDER BY id;

  -- 定义存储数据的变量.
  v_main_data  test_main%ROWTYPE;

BEGIN
  -- 打开游标.
  OPEN c_test_main;

  -- 填充数据.
  FETCH FIRST FROM c_test_main INTO v_main_data;
  INSERT INTO log_table VALUES ('游标第一行:' || v_main_data.value);
  
  -- 填充数据.
  FETCH LAST FROM c_test_main INTO v_main_data;
  INSERT INTO log_table VALUES ('游标最末行:' || v_main_data.value);
  
  -- 填充数据.
  FETCH ABSOLUTE 3 FROM c_test_main INTO v_main_data;
  INSERT INTO log_table VALUES ('游标绝对第3行:' || v_main_data.value);

  -- 填充数据.
  FETCH RELATIVE 2 FROM c_test_main INTO v_main_data;
  INSERT INTO log_table VALUES ('游标相对第2行:' || v_main_data.value);
  
  -- 填充数据.
  FETCH PRIOR  FROM c_test_main INTO v_main_data;
  INSERT INTO log_table VALUES ('游标上一行:' || v_main_data.value);

  -- 填充数据.
  FETCH NEXT  FROM c_test_main INTO v_main_data;
  INSERT INTO log_table VALUES ('游标下一行:' || v_main_data.value);  
  
  -- 关闭游标
  CLOSE c_test_main;
END;
$$
LANGUAGE plpgsql;


Test=# select TestCursorScroll() ;
 testcursorscroll
------------------

(1 行记录)


Test=# select * from log_table;
       log_text
----------------------
 游标第一行:ONE1
 游标最末行:ONETHREE
 游标绝对第3行:FOUR1
 游标相对第2行:ONETWO
 游标上一行:ONEONE
 游标下一行:ONETWO
(6 行记录)



带参数的游标 

这里同时需要使用前面外键约束的 test_sub 表 



-- 清空日志表.
Test=# truncate table log_table;
TRUNCATE TABLE





CREATE OR REPLACE FUNCTION TestCursorMainSub() RETURNS void AS
$$
DECLARE
  -- 定义游标(主表).
  c_test_main CURSOR FOR
    SELECT id, value FROM test_main;
  -- 保存主表游标数据的变量
  v_main_data  test_main%ROWTYPE;
  
  -- 定义游标(子表).
  c_test_sub CURSOR(p_main_id INT) IS
    SELECT id, main_id, value
    FROM test_sub
    WHERE main_id = p_main_id;
  -- 保存子表游标数据的变量
  v_sub_data  test_sub%ROWTYPE;
BEGIN

  -- 打开游标(主表).
  OPEN c_test_main;

  -- 开始循环处理(主表).
  LOOP  
    -- 填充数据(主表).
    FETCH c_test_main INTO v_main_data;
    -- 假如没有检索到(主表)数据,结束循环处理
    Exit when NOT found;

    -- 主表每一行的实际操作.
    INSERT INTO log_table VALUES ( 'Main:' || v_main_data.value );

    -- 打开游标(子表).
    OPEN c_test_sub(v_main_data.id);

    -- 开始循环处理(子表).
    LOOP
      -- 填充数据(子表).
      FETCH c_test_sub INTO v_sub_data;
      -- 假如没有检索到(主表)数据,结束循环处理
      Exit when NOT found;

      -- 子表每一行的实际操作.
      INSERT INTO log_table VALUES ( '-->Sub:' || v_sub_data.value );
    END LOOP;
    -- 关闭游标(子表).
    CLOSE c_test_sub;
  END LOOP; 
  
  -- 关闭游标(主表).
  CLOSE c_test_main;
END;
$$
LANGUAGE plpgsql;



Test=# select TestCursorMainSub();
 testcursormainsub
-------------------

(1 行记录)


Test=# select * from log_table;
    log_text
-----------------
 Main:ONE
 -->Sub:ONEONE
 Main:TWO
 -->Sub:TWOTWO
 Main:FOUR
 -->Sub:FOURFOUR
(6 行记录)




用于更新的游标 




CREATE OR REPLACE FUNCTION TestUpdateCursor() RETURNS void AS
$$
DECLARE
  -- 定义游标.
  c_test_main CURSOR FOR
    SELECT id, value FROM test_main FOR UPDATE ;
  -- 定义存储数据的变量.
  v_main_data  test_main%ROWTYPE;

BEGIN
  -- 打开游标.
  OPEN c_test_main;

  LOOP  
    -- 填充数据.
    FETCH c_test_main INTO v_main_data;
    -- 假如没有检索到数据,结束循环处理
    Exit when NOT found;
	
	-- 游标每一行的实际操作.
    
	-- 更新数据.
    UPDATE 
      test_main
    SET
      value = value || '1'
    WHERE 
      CURRENT OF c_test_main;

  END LOOP; 

  
  -- 关闭游标
  CLOSE c_test_main;
END;
$$
LANGUAGE plpgsql;



Test=# select TestUpdateCursor();
 testupdatecursor
------------------

(1 行记录)


Test=# select * from test_main;
 id | value
----+-------
  1 | ONE1
  2 | TWO1
  4 | FOUR1
(3 行记录)

FOR的使用 



-- 清空日志表.
Test=# truncate table log_table;
TRUNCATE TABLE



CREATE OR REPLACE FUNCTION TestCursorFor() RETURNS void AS
$$
DECLARE
  -- 定义存储数据的变量.
  v_main_data RECORD;
BEGIN

  FOR v_main_data IN SELECT id, value FROM test_main LOOP
	-- 每一行的实际操作.
    INSERT INTO log_table VALUES (v_main_data.value);
  END LOOP; 

END;
$$
LANGUAGE plpgsql;




Test=# SELECT TestCursorFor();
 testcursorfor
---------------

(1 行记录)


Test=# select * from log_table;
 log_text
----------
 ONE1
 TWO1
 FOUR1
(3 行记录)

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值