欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 » Oracle数据库应用教程 » 正文

Oracle学习教程:动态SQL与游标详解

创建时间:2012年04月04日 12:31  阅读次数:(8145)
分享到:

动态 SQL


动态 SQL是指在PL/SQL程序执行时生成的 SQL 语句
编译程序对动态 SQL 不做处理,而是在程序运行时动态构造语句、对语句进行语法分析并执行
DDL 语句命令和会话控制语句不能在 PL/SQL 中直接使用,但是可以通过动态 SQL 来执行
执行动态 SQL 的语法:
EXECUTE IMMEDIATE dynamic_sql_string
[INTO  define_variable_list]
[USING bind_argument_list];

示例:
DECLARE
  sql_stmt VARCHAR2(200);
  emp_id NUMBER(4) := 7566;
  emp_rec emp%ROWTYPE;
BEGIN
EXECUTE IMMEDIATE 
‘CREATE TABLE COM (id NUMBER,com NUMBER)’;

sql_stmt := 'SELECT * FROM emp WHERE empno = :id';
EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id;
END;

游标简介


游标是指逐行处理查询结果,以编程的方式访问数据
游标的类型:
1,隐式游标.2,显式游标.3,REF 游标
注意:REF 游标用于处理运行时才能确定的动态 SQL 查询的结果

隐式游标
在PL/SQL中使用DML语句时自动创建隐式游标,隐式游标自动声明、打开和关闭,其名为 SQL.
通过检查隐式游标的属性可以获得最近执行的DML 语句的信息.
隐式游标的属性有:
%FOUND – SQL 语句影响了一行或多行时为 TRUE
%NOTFOUND – SQL 语句没有影响任何行时为TRUE
%ROWCOUNT – SQL 语句影响的行数
%ISOPEN  - 游标是否打开,隐式游标始终为FALSE

示例1:只有在 DML 语句影响一行或多行时,才返回 True
SQL > SET SERVEROUTPUT ON
SQL > BEGIN
UPDATE toys SET toyprice=270
WHERE toyid= 'P005';
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE(‘表已更新');
END IF;
 END;
/

示例2:如果 DML 语句不影响任何行,则返回 True 
SQL > SET SERVEROUTPUT ON
SQL > DECLARE
   v_TOYID TOYS.ID%type := '&TOYID';
   v_TOYNAME TOYS.NAME%Type := '&TOYNAME';
 BEGIN
   UPDATE TOYS SET NAME = v_TOYNAME
   WHERE toyid=v_TOYID;
   IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('编号未找到。');
  ELSE
DBMS_OUTPUT.PUT_LINE(‘表已更新');
END IF;
 END;
/

示例3:返回 DML 语句影响的行数
SQL > SET SERVEROUTPUT ON 
SQL > BEGIN
UPDATE emp
SET ename= 'Robert'
WHERE empno=‘7369';
DBMS_OUTPUT.PUT_LINE (SQL%ROWCOUNT);
 END;
 /

SELECT INTO 语句
示例1:如果没有与SELECT INTO语句中的条件匹配的行,将引发NO_DATA_FOUND异常
SQL > SET SERVEROUTPUT ON
SQL > DECLARE 
empid VARCHAR2(10);
desig VARCHAR2(10);
 BEGIN
empid:= '&Employeeid';
SELECT designation INTO desig 
FROM employee WHERE empno=empid;
 EXCEPTION
WHEN NO_DATA_FOUND THEN
  DBMS_OUTPUT.PUT_LINE('职员未找到');
 END;
 /

示例2:如果 SELECT INTO 语句返回多个值,将引发TOO_MANY_ROWS异常
SQL > SET SERVEROUTPUT ON
SQL > DECLARE 
empid VARCHAR2(10);
 BEGIN
SELECT empno INTO empid FROM emp;
 EXCEPTION
WHEN TOO_MANY_ROWS THEN
  DBMS_OUTPUT.PUT_LINE('该查询提取多行');
 END;
 /

显式游标


显式游标在 PL/SQL 块的声明部分定义查询,该查询可以返回多行
显式游标的操作过程:


任务2:查询符合条件的多个员工的信息使用显式游标
SQL > SET SERVEROUTPUT ON
SQL > DECLARE
 v_ename EMP.ENAME%TYPE;
 v_salary EMP.SAL%TYPE;
--声明游标
 CURSOR c_emp IS SELECT ename,sal FROM emp;
 BEGIN
--打开游标
   OPEN c_emp;
 LOOP
--提取行
   FETCH c_emp INTO v_ename,v_salary;
   EXIT WHEN c_emp%NOTFOUND;
   DBMS_OUTPUT.PUT_LINE('Salary of Employee '|| v_ename || ' is: '|| v_salary);
  end loop;
--关闭游标
CLOSE  c_emp;
 END;
/

任务3 :统计不同部门的员工信息 使用带参数的显式游标
SQL > SET SERVEROUTPUT ON
SQL > DECLARE
 dept_code emp.deptno%TYPE;
 emp_code  emp.empno%TYPE;
 emp_name  emp.ename%TYPE;
CURSOR emp_cur (deptparam NUMBER) IS
 SELECT empno, ename FROM emp
 WHERE deptno= deptparam;
 BEGIN
  dept_code := &部门编号;
  OPEN emp_cur(dept_code);
LOOP
FETCH emp_cur INTO emp_code, emp_name;
EXIT WHEN emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(emp_code||' '|| emp_name);
   END LOOP;
CLOSE emp_cur;
 END;

使用显式游标更新行
允许使用游标删除或更新活动集中的行
声明游标时必须使用 SELECT … FOR UPDATE语句
CURSOR <cursor_name > IS
  SELECT statement FOR UPDATE;

UPDATE <table_name >
SET <set_clause >
WHERE CURRENT OF <cursor_name >
--删除的语法 
DELETE FROM <table_name >
WHERE CURRENT OF <cursor_name >

任务4:修改或删除满足条件的多个用户信息 使用显式游标更新行
例:查询EMP表中部门号为20的员工目前的薪水。 SQL > select empno,deptno,sal from emp where deptno=20;

例:利用UPDATE语句和WHERE条件中的CURRENT OF子句,将EMP表中部门号为20的员工提高10%的薪水。 
SQL > SET SERVEROUTPUT ON
SQL > declare 
cursor salcur(depno number) is
select sal from emp where deptno =depno for update of sal;
 new_sal number;
   begin
 for currentsal in salcur(20) loop
 new_sal:=currentsal.sal;
update emp set sal=1.1*new_sal where current of salcur;
   end loop;  end;
 /

循环游标
循环游标用于简化游标处理代码,当用户需要从游标中提取所有记录时使用,循环游标的语法如下:
FOR < record_name> IN
 < corsor_name[(parameter[,parameter]...)] 
 | (query_difinition>
 LOOP
<executable statements >
 END LOOP;

示例:
SQL > SET SERVER OUTPUT ON
SQL >  DECLARE
 CURSOR c_dept IS SELECT deptno,dname FROM dept ORDER BY deptno;
 CURSOR c_emp (p_dept VARCHAR2) IS
  SELECT ename,sal  FROM emp  WHERE deptno=p_dept  ORDER BY ename;
 v_tot_salary EMP.SAL%TYPE;
 BEGIN
   FOR r_dept IN c_dept LOOP 
   DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
   v_tot_salary:=0;
 FOR r_emp IN c_emp(r_dept.deptno) LOOP
DBMS_OUTPUT.PUT_LINE('Name: ' || r_emp.ename || ' salary: ' || r_emp.sal);
v_tot_salary:=v_tot_salary+r_emp.sal;
 END LOOP;
 DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
  END LOOP;
END;

REF 游标和游标变量
REF 游标和游标变量用于处理运行时动态执行的 SQL 查询,创建游标变量需要两个步骤:
1,声明 REF 游标类型
2,声明 REF 游标类型的变量
用于声明 REF 游标类型的语法为:
TYPE <ref_cursor_name > IS REF CURSOR
[RETURN <return_type >];

打开游标变量的语法如下:
OPEN cursor_name FOR select_statement;

声明强类型的 REF 游标
Type?emp_refcur_t?is?ref?cursor return?employee%rowtype; 
order_cur ?emp_refcur_t;

声明弱类型的 REF 游标
TYPE my_ctype IS REF CURSOR;
stud_cur my_ctype;

示例:
SQL > DECLARE
--声明REF游标类型
TYPE toys_curtype IS REF CURSOR
  RETURN toys%ROWTYPE;
--声明游标变量
 toys_curvar toys_curtype;
toys_rec toys%ROWTYPE;
 BEGIN
   OPEN toys_curvar FOR
  SELECT * FROM toys;
   FETCH toys_curvar INTO toys_rec;
   ...
   CLOSE toys_curvar;
 END;

游标变量的优点和限制


游标变量的功能强大,可以简化数据处理。游标变量的优点有:
1,可从不同的 SELECT 语句中提取结果集
2,可以作为过程的参数进行传递
3,可以引用游标的所有属性
4,可以进行赋值运算

使用游标变量的限制:
1,不能在程序包中声明游标变量
2,FOR UPDATE子句不能与游标变量一起使用
3,不能使用比较运算符

使用游标变量执行动态 SQL
示例:
DECLARE
  r_emp emp%ROWTYPE;
  TYPE c_type IS REF CURSOR;
  cur c_type;
  p_salary NUMBER;
BEGIN
  p_salary := 2500;
  OPEN cur FOR 'select * from emp where sal >:1
order by sal desc'
  USING p_salary;
  DBMS_OUTPUT.PUT_LINE('薪水大于'|| p_salary ||'的员工有:');
  LOOP
FETCH cur INTO r_emp;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('编号:'|| r_emp.empno
  || ' 姓名:' || r_emp.ename|| ' 薪水:' || r_emp.sal );
  END LOOP;
  CLOSE cur;
END;
u
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 73+49=? 的结果(结果是:122)
结  果: