DMSQL 程序为用户提供了游标,供用户对查询到的多行数据进行逐条处理。游标可以从多条数据记录的结果集中每次提取一条记录供用户访问处理,通过循环控制,遍历结果集中的所有记录。
达成梦数据库中的游标分为静态游标和动态游标,其中静态游标又可分为显式游标和隐式游标。
一、静态游标
静态游标是只读游标,它总是按照打开游标时的原样显示结果集,在编译时就能确定静态游标使用的查询。
1.隐式游标
每当用户在 DMSQL 程序中执行一个DML语句(INSERT、UPDATE、DELETE)或者 SELECT …INTO 语句时,DMSQL 程序都会自动声明一个隐式游标并管理这个游标。
隐式游标不必专门去声明,数据库自动为我们做好了后台工作,如定义、打开、取值及关闭操作,由达梦数据库自动完成,用户通过隐式游标的相关属性,来完成相应的操作。隐式游标的名称为“SQL”,用户可以通过隐式游标获取语句执行的一些信息。DMSQL 程序中的每个游标都有%FOUND、%NOTFOUND、%ISOPEN 和%ROWCOUNT 四个属性,对于 隐式游标,这四个属性的意义如下:
- %FOUND:语句是否修改或查询到了记录,是返回 TRUE,否则返回 FALSE;
- %NOTFOUND:语句是否未能成功修改或查询到记录,是返回 TRUE,否则返回FALSE;
- %ISOPEN:游标是否打开。是返回 TRUE,否返回 FALSE。由于系统在语句执行
完成后会自动关闭隐式游标,因此隐式游标的%ISOPEN 属性永远为 FALSE; - %ROWCOUNT:DML 语句执行影响的行数,或 SELECT…INTO 语句返回的行数。
例如:
总共1个语句正依次执行...
[执行语句1]:
DECLARE
v_name varchar;
v_date date;
BEGIN
SELECT EMPLOYEE_NAME, HIRE_DATE into v_name, v_date FROM
DMHR.EMPLOYEE;
IF SQL%FOUND THEN
PRINT v_name||','||v_date;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
PRINT 'NO DATA FOUND!';
WHEN TOO_MANY_ROWS
THEN
PRINT 'TOO MANY ROWS!';
END;
执行成功, 执行耗时0毫秒. 执行号:86
TOO MANY ROWS!
影响了0条记录
1条语句执行成功
在上面例子中我们可以看到,通过直接利用%FOUND属性,判断游标中集合各字段值是否存在。同时,可以看到,select …into主要是单行结果集的处理,对于多行结果查询异常处理模块捕获到了异常。下面是查询为空时捕获异常的例子:
总共1个语句正依次执行...
[执行语句1]:
DECLARE
v_name varchar;
v_date date;
BEGIN
SELECT EMPLOYEE_NAME, HIRE_DATE into v_name, v_date FROM
DMHR.EMPLOYEE WHERE EMPLOYEE_ID='100001';
IF SQL%FOUND THEN
PRINT v_name||','||v_date;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
PRINT 'NO DATA FOUND!';
WHEN TOO_MANY_ROWS
THEN
PRINT 'TOO MANY ROWS!';
END;
执行成功, 执行耗时0毫秒. 执行号:88
NO DATA FOUND!
影响了0条记录
1条语句执行成功
这段过程中,查询结果集是为空,SQL%FOUND属性判断后跳过打印,最终通过异常处理模块正常捕获到。
下面是模块正常执行时,未出现异常的例子:
总共1个语句正依次执行...
[执行语句1]:
DECLARE
v_name varchar;
v_date date;
BEGIN
SELECT EMPLOYEE_NAME, HIRE_DATE into v_name, v_date FROM
DMHR.EMPLOYEE WHERE EMPLOYEE_ID='1001';
IF SQL%FOUND THEN
PRINT v_name||','||v_date;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
PRINT 'NO DATA FOUND!';
WHEN TOO_MANY_ROWS
THEN
PRINT 'TOO MANY ROWS!';
END;
执行成功, 执行耗时0毫秒. 执行号:89
马学铭,2008-05-30
影响了1条记录
1条语句执行成功
上面这段处理过程,查询只有一条匹配结果,正常打印了记录中的指定字段内容。
通过上面的例子,可以看到,隐式游标使用上较为方便,省去了游标定义、打开、关闭等操作,但使用场景上有局限性,程序中限于INSERT、UPDATE、DELETE、SELECT …INTO 等语句。
2.显式游标
显式游标指向一个查询语句执行后的结果集区域。当需要处理返回多条记录的查询时,应显式地定义游标以处理结果集地每一行。
使用显式游标一般包括四个步骤:
(1)定义游标:在 DMSQL 程序的声明部分定义游标,声明游标及其关联的查询语句;
(2)打开游标:执行游标关联的语句,将查询结果装入游标工作区,将游标定位到结果集的第一行之前;
(3)拨动游标:根据应用需要将游标位置移动到结果集的合适位置;
(4)关闭游标:游标使用完后应关闭,以释放其占有的资源。
下面的程序则是一个显式游标使用的例子。
DECLARE
v_name VARCHAR(50);
v_phone VARCHAR(50);
c1 CURSOR;
BEGIN
OPEN c1 FOR SELECT NAME,PHONE FROM PERSON.PERSON A,RESOURCES.EMPLOYEE B
WHERE A.PERSONID=B.PERSONID;
LOOP
FETCH c1 INTO v_name,v_phone;
EXIT WHEN c1%NOTFOUND;
PRINT 'name:' || v_name || ' phone number: ' ||v_phone;
END LOOP;
CLOSE c1;
END;
/
二、动态游标
动态游标在声明部分只是先声明一个游标类型的变量,并不指定其关联的查询语句,在执行部分打开游标时才指定查询语句。动态游标的使用主要在定义和打开时与显式游标不同。
下面的例子则是一个动态游标使用的过程。
DECLARE
my_ename CHAR(10);
my_empno NUMERIC(4);
my_sal NUMERIC(7,2);
c1 CURSOR;
BEGIN
OPEN C1 FOR SELECT * FROM OTHER.EMPSALARY;
LOOP
FETCH c1 INTO my_ename, my_empno, my_sal;
EXIT WHEN c1%NOTFOUND;
PRINT '姓名:'||my_ename || '工号:' || my_empno || ' 薪水:' || my_sal;
END LOOP;
CLOSE c1;
END;
/
动态游标关联的查询语句还可以带有参数,参数以“?”指定,同时在打开游标语句中使用 USING 子句指定参数,且参数的个数和类型与语句中的“?”必须一一匹配。下面的例子说明了如何使用关联的语句中带有参数的动态游标。
DECLARE
str VARCHAR;
CURSOR csr;
BEGIN
OPEN csr FOR 'SELECT LOGINID FROM RESOURCES.EMPLOYEE WHERE TITLE =? OR
TITLE =?' USING '销售经理','总经理';
LOOP
FETCH csr INTO str;
EXIT WHEN csr%NOTFOUND;
PRINT str;
END LOOP;
CLOSE csr;
END;
/
三、小结
达梦数据库中游标为我们提供了一种便捷处理结果集的方法,允许应用程序对查询语句返回的结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作,它还提供对基于游标位置而对表中数据进行删除或更新的能力,展示了数据库强大的运算处理能力。