Oracle學習教程:動態SQL與遊標詳解

動態 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;
相關文章
相關標籤/搜索