摘要:游标是一种数据处理方法,提供了在查询结果集中进行逐行遍历浏览数据的方法,也可以将游标当做上下文区域的句柄或者指针,借助游标对指定位置的数据进行查询与处理。

本文分享自华为云社区《GaussDB(DWS) SQL进阶之PLSQL(二)-游标》,作者: xxxsql123 。

前言

游标是一种数据处理方法,提供了在查询结果集中进行逐行遍历浏览数据的方法,也可以将游标当做上下文区域的句柄或者指针,借助游标对指定位置的数据进行查询与处理,本章我们主要聚焦于GaussDB(DWS)存储过程中的游标使用。

显式游标

显示游标主要用于处理存储过程中的查询结果集是游标常用的用法,具体分为如下几个步骤:

Step 1 定义游标:

静态游标定义:

即定义一个游标名以及与其相对应的SELECT语句

语法图:

示例如下:

--在存储过程的DECLARE中声明游标定义
CURSOR C1 IS
SELECT section_name, place_id FROM hr.sections WHERE section_id <= 50;
CURSOR C2(sect_id INTEGER) IS
SELECT section_name, place_id FROM hr.sections WHERE section_id <= sect_id;

动态游标定义:

即ref游标,可以通过静态的SQL语句在合适的时候动态的打开游标。先定义ref游标类型,后面通过open for动态绑定SELECT语句

语法图:

示例如下:

--在存储过程的DECLARE中声明游标定义
TYPE CURSOR_TYPE IS REF CURSOR;

同时GaussDB(DWS)做了Oracle兼容,支持sys_refcursor动态游标类型,函数或存储过程可以通过sys_refcursor参数传入或传出游标结果集合,函数也可以通过返回sys_refcursor来返回游标结果集合。

语法图:

示例如下:

--在存储过程的DECLARE中声明游标定义
C1 SYS_REFCURSOR;

Step 2 打开游标:

静态游标打开:

即执行游标对应的SELECT语句,将结果集放入工作区,将游标的指针指向工作区的起始位置。

语法图:

示例如下:

--在存储过程的BODY中打开游标
OPEN C1;
OPEN C2(10);

动态游标打开:

通过OPEN FOR语句打开动态游标,通过USING对SELECT语句进行动态绑定。

语法图:

示例如下:

--在存储过程的BODY中打开游标
SQL_STR := 'SELECT section_name, place_id FROM hr.sections WHERE section_id <= :DEPT_NO;';
OPEN C3 FOR SQL_STR USING 50;

Step 3 提取游标数据:

即提取游标指针指向的数据

语法图:

示例:

--在存储过程的BODY中执行
FETCH C3 INTO DEPT_NAME, DEPT_LOC;

Step 4 循环处理游标数据:

提取数据后可以基于存储过程的语句灵活发挥

例如,给工资低于3000的员工增加500块钱工资

--在存储过程的BODY中执行
LOOP
FETCH C INTO V_EMPNO, V_SAL;
EXIT WHEN C%NOTFOUND;
IF V_SAL<=3000 THEN
UPDATE hr.staffs_t1 SET salary =salary + 500 WHERE staff_id = V_EMPNO;
END IF;
END LOOP;

Step 5 关闭游标:

在处理完游标的数据后,应及时释放游标,以便释放游标所占用系统资源,游标关闭后工作区将变成无效,不能再使用FETCH语句获取其中数据。关闭后的游标可以使用OPEN语句重新打开。

语法图:

--在存储过程的BODY中执行
CLOSE C1;--关闭游标

游标属性

我们可以通过游标的属性来了解当前游标的状态。下面将介绍4中游标属性:

※ %FOUND布尔型属性:当最近一次读记录时成功返回,则值为TRUE。

※ %NOTFOUND布尔型属性:与%FOUND相反。

※ %ISOPEN布尔型属性:当游标已打开时返回TRUE。

※ %ROWCOUNT数值型属性:返回已从游标中读取的记录数。

示例:

 OPEN C1;--打开游标
LOOP
--通过游标取值
FETCH C1 INTO DEPT_NAME, DEPT_LOC;
EXIT WHEN C1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(DEPT_NAME||'---'||DEPT_LOC);
END LOOP;
CLOSE C1;--关闭游标

接下来我们将结合前面所学习的知识,在存储过程运用显示游标。

数据准备:

CREATE SCHEMA hr;
SET CURRENT_SCHEMA = 'hr';
DROP TABLE IF EXISTS sections;
CREATE TABLE sections(section_id INT, section_name VARCHAR(100), place_id NUMBER(4)) DISTRIBUTE BY HASH(section_id);
INSERT INTO sections VALUES (1, 'section_name1', 1),(2, 'section_name2', 2),(3, 'section_name3', 3);

显示游标使用示例:

--游标参数的传递方法。
CREATE OR REPLACE PROCEDURE cursor_proc1()
AS
DECLARE
DEPT_NAME VARCHAR(100);
DEPT_LOC NUMBER(4);
--定义游标
CURSOR C1 IS
SELECT section_name, place_id FROM hr.sections WHERE section_id <= 50;
CURSOR C2(sect_id INTEGER) IS
SELECT section_name, place_id FROM hr.sections WHERE section_id <= sect_id;
TYPE CURSOR_TYPE IS REF CURSOR;
C3 CURSOR_TYPE;
SQL_STR VARCHAR(100);
BEGIN
OPEN C1;--打开游标
LOOP
--通过游标取值
FETCH C1 INTO DEPT_NAME, DEPT_LOC;
EXIT WHEN C1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(DEPT_NAME||'---'||DEPT_LOC);
END LOOP;
CLOSE C1;--关闭游标 OPEN C2(10);
LOOP
FETCH C2 INTO DEPT_NAME, DEPT_LOC;
EXIT WHEN C2%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(DEPT_NAME||'---'||DEPT_LOC);
END LOOP;
CLOSE C2; SQL_STR := 'SELECT section_name, place_id FROM hr.sections WHERE section_id <= :DEPT_NO;';
OPEN C3 FOR SQL_STR USING 50;
LOOP
FETCH C3 INTO DEPT_NAME, DEPT_LOC;
EXIT WHEN C3%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(DEPT_NAME||'---'||DEPT_LOC);
END LOOP;
CLOSE C3;
END;
/ CALL cursor_proc1(); DROP PROCEDURE cursor_proc1;

执行结果:

postgres=# CALL cursor_proc1();
section_name3---3
section_name1---1
section_name2---2
section_name1---1
section_name2---2
section_name3---3
section_name1---1
section_name2---2
section_name3---3
cursor_proc1
-------------- (1 row)

SYS_REFCURSOR游标示例:

--SYS_REFCURSOR类型做为函数参数
CREATE OR REPLACE PROCEDURE proc_sys_ref(O OUT SYS_REFCURSOR)
IS
C1 SYS_REFCURSOR;
BEGIN
OPEN C1 FOR SELECT section_ID FROM HR.sections ORDER BY section_ID;
O := C1;
END;
/ DECLARE
C1 SYS_REFCURSOR;
TEMP NUMBER(4);
BEGIN
proc_sys_ref(C1);
LOOP
FETCH C1 INTO TEMP;
DBMS_OUTPUT.PUT_LINE(C1%ROWCOUNT);
EXIT WHEN C1%NOTFOUND;
END LOOP;
END;
/ --删除存储过程
DROP PROCEDURE proc_sys_ref;

执行结果:

postgres=# DECLARE
postgres-# C1 SYS_REFCURSOR;
postgres-# TEMP NUMBER(4);
postgres-# BEGIN
postgres$# proc_sys_ref(C1);
postgres$# LOOP
postgres$# FETCH C1 INTO TEMP;
postgres$# DBMS_OUTPUT.PUT_LINE(C1%ROWCOUNT);
postgres$# EXIT WHEN C1%NOTFOUND;
postgres$# END LOOP;
postgres$# END;
postgres$# /
1
2
3
3
ANONYMOUS BLOCK EXECUTE

隐式游标

对于非SELECT语句,例如UPDATE,DELETE操作,系统会自动的未这些操作设置游标,这些有系统隐含创建的游标即隐式游标。隐式游标的定义,打开,取值,关闭操作均有系统自动的完成,无需用户进行处理,用户只能通过隐式游标的相关属性完成相应的操作。

隐式游标属性:

※ SQL%FOUND布尔型属性:当最近一次读记录时成功返回,则值为TRUE。

※ SQL%NOTFOUND布尔型属性:与%FOUND相反。

※ SQL%ROWCOUNT数值型属性:返回已从游标中读取得记录数。

※ SQL%ISOPEN布尔型属性:取值总是FALSE。SQL语句执行完毕立即关闭隐式游标。

隐式游标示例如下:

--删除EMP表中某部门的所有员工,如果该部门中已没有员工,则在DEPT表中删除该部门。
CREATE TABLE hr.staffs_t1 AS TABLE hr.staffs;
CREATE TABLE hr.sections_t1 AS TABLE hr.sections; CREATE OR REPLACE PROCEDURE proc_cursor3()
AS
DECLARE
V_DEPTNO NUMBER(4) := 100;
BEGIN
DELETE FROM hr.staffs WHERE section_ID = V_DEPTNO;
--根据游标状态做进一步处理
IF SQL%NOTFOUND THEN
DELETE FROM hr.sections_t1 WHERE section_ID = V_DEPTNO;
END IF;
END;
/ CALL proc_cursor3(); --删除存储过程和临时表
DROP PROCEDURE proc_cursor3;
DROP TABLE hr.staffs_t1;
DROP TABLE hr.sections_t1;

以上就是在GuassDB(DWS)的存储过程中游标的基本使用。

总结

GuassDB(DWS)的游标使用在postgresql的基础上做了对Oracle的语法兼容,存储过程中的游标功能对于原来依赖Oracle的系统可以平滑的迁移。同时由于GuassDB(DWS)是分布式架构,和postgresql本身以及GuassDB(DWS)的单机模式上游标的行为细节上会略有不同,例如事务中的DECLARE CURSOR由于分布式和单机的实现差异导致在pg_cursors视图查询结果差异等。

接下来的时间里将会像大家逐步介绍存储过程的自定义用户类型等章节,敬请期待~

想了解GuassDB(DWS)更多信息,欢迎微信搜索“GaussDB DWS”关注微信公众号,和您分享最新最全的PB级数仓黑科技,后台还可获取众多学习资料哦~

点击关注,第一时间了解华为云新鲜技术~

带你聚焦GaussDB(DWS)存储时游标使用的更多相关文章

  1. 一文详解数仓GaussDB(DWS) 函数出参带出方式

    摘要:本文主要讲解DWS函数出参带出方式. 本文分享自华为云社区<GaussDB(DWS)功能 -- 函数出参 #[玩转PB级数仓GaussDB(DWS)]>,作者:譡里个檔 . DWS的 ...

  2. 从数据仓库双集群系统模式探讨,看GaussDB(DWS)的容灾设计

    摘要:本文主要是探讨OLAP关系型数据库框架的数据仓库平台如何设计双集群系统,即增强系统高可用的保障水准,然后讨论一下GaussDB(DWS)的容灾应该如何设计. 当前社会.企业运行当中,大数据分析. ...

  3. 由两个问题引发的对GaussDB(DWS)负载均衡的思考

    摘要:GaussDB(DWS)的负载均衡通过LVS+keepAlived实现.对于这种方式,需要思考的问题是,CN的返回结果是否会经过LVS,然后再返回给前端应用?如果经过LVS,那么,LVS会不会成 ...

  4. 探索GaussDB(DWS)的过程化SQL语言能力

    摘要:在当前GaussDB(DWS)的能力中主要支持两种过程化SQL语言,即基于PostgreSQL的PL/pgSQL以及基于Oracle的PL/SQL.本篇文章我们通过匿名块,函数,存储过程向大家介 ...

  5. 十八般武艺玩转GaussDB(DWS)性能调优(三):好味道表定义

    摘要:表结构设计是数据库建模的一个关键环节,表定义好坏直接决定了集群的有效容量以及业务查询性能,本文从产品架构.功能实现以及业务特征的角度阐述在GaussDB(DWS)的中表定义时需要关注的一些关键因 ...

  6. GaussDB(DWS)中共享消息队列实现的三大功能

    摘要:本文将详细介绍GaussDB(DWS)中共享消息队列的实现. 本文分享自华为云社区<GaussDB(DWS)CBB组件之共享消息队列介绍>,作者:疯狂朔朔. 1)共享消息队列是什么? ...

  7. 5步带你入门GaussDB(DWS)的GDS导入导出

    摘要:本篇文档为使用GDS导入示例的具体简单步骤和示例. 本文分享自华为云社区<带你快速入门GDS导入导出,玩转PB级数仓GaussDB(DWS)>,作者: yd_220527686. 1 ...

  8. GaussDB(DWS)应用实战:对被视图引用的表进行DDL操作

    摘要:GaussDB(DWS)是从Postgres演进过来的,像Postgres一样,如果表被视图引用的话,特定场景下,部分DDL操作是不能直接执行的. 背景说明 GaussDB(DWS)是从Post ...

  9. 详解GaussDB(DWS) explain分布式执行计划

    摘要:本文主要介绍如何详细解读GaussDB(DWS)产生的分布式执行计划,从计划中发现性能调优点. 前言 执行计划(又称解释计划)是数据库执行SQL语句的具体步骤,例如通过索引还是全表扫描访问表中的 ...

  10. GaussDB(DWS)应用实践丨负载管理与作业排队处理方法

    摘要:本文用来总结一些GaussDB(DWS)在实际应用过程中,可能出现的各种作业排队的情况,以及出现排队时,我们应该怎么去判断是否正常,调整一些参数,让资源分配与负载管理更符合当前的业务:或者在作业 ...

随机推荐

  1. 浅析 C# Console 控制台为什么也会卡死

    一:背景 1. 讲故事 在分析旅程中,总会有几例控制台的意外卡死导致的生产事故,有经验的朋友都知道,控制台卡死一般是动了 快速编辑窗口 的缘故,截图如下: 虽然知道缘由,但一直没有时间探究底层原理,市 ...

  2. C#工作流——elsa-workflows

    介绍 Elsa Workflows 是一个功能强大且灵活的执行引擎,封装为一组开源 .NET 库,旨在为 .NET 应用程序注入工作流功能. 借助 Elsa,开发人员可以将逻辑直接编织到他们的系统中, ...

  3. JavaScript 语法:流程控制语句

    作者:WangMin 格言:努力做好自己喜欢的每一件事 JavaScript流程控制语句的三种基本结构:顺序结构,选择结构,循环结构 顺序结构 从上到下执行的代码就是顺序结构,程序默认就是由上到下顺序 ...

  4. DM数据库 回表优化案例

    京华开发一哥们找我优化条SQL,反馈在DM数据库执行时间很慢需要 40s 才能出结果,安排. 原SQL: SELECT A.IND_CODE, A.IND_NAME AS "specialN ...

  5. (Good topic)四因数 (leetcode 181周赛T2)

     四因数难度中等1收藏分享切换为英文关注反馈给你一个整数数组 nums,请你返回该数组中恰有四个因数的这些整数的各因数之和. 如果数组中不存在满足题意的整数,则返回 0 .   示例: 输入:nums ...

  6. Python根据输入的公司编号、名称、网址,格式化输出公司信息。其中1)冒号统一为英文冒号,编号占6位,不足6位的前面补0。编号后面是制表符。

    根据输入的公司编号.名称.网址,格式化输出公司信息.其中 1)冒号统一为英文冒号,编号占6位,不足6位的前面补0.编号后面是制表符. 2)"公司名称:" 后面输出字符串占8位,左对 ...

  7. 我最喜欢的白版应用,AI加持的新功能开源!强烈推荐

    Excalidraw 把他们的文本到图表的功能开源了 Excalidraw是一个虚拟白板应用,专门用于绘制类似手绘的图表.它提供了一个无限的.基于画布的白板,具有手绘风格,支持多种功能. 之前我分享的 ...

  8. [计蒜客20191103D] 坐车

    n 个学生将要坐车去餐厅,每辆车最多可以坐 5 个人并且出于对环境的考虑他们不会使用多余的车.车的速度为每秒 1 个单位.现在 ii 号同学需要去 \(i\) 号点停 5 分钟(此时整车都在 i 号点 ...

  9. SpringCloudAlibaba-OSS文件上传

    一.引入相关依赖 <dependencyManagement> <dependencies> <dependency> <groupId>com.ali ...

  10. Linux配置成代理服务器

    简介: 代理服务器(Proxy Server)是一种位于计算机网络中的中间服务器,它充当了客户端和目标服务器之间的中介,用于转发客户端请求并获取目标服务器的响应.代理服务器的主要功能包括以下几点: 什 ...