• oracle ql/sql 相关语法解析


    这篇文章主要介绍了Oracle中游标Cursor基本用法详解,还是比较全面的,具有一定参考价值,需要的朋友可以了解下。
     

    查询

      SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的
    返回值被赋予INTO子句中的变量,变量的声明是在DELCARE中。SELECT INTO语法如下:

      SELECT [DISTICT|ALL]{*|column[,column,...]}
      INTO (variable[,variable,...] |record)
      FROM {table|(sub-query)}[alias]
      WHERE............

      PL/SQL中SELECT语句只返回一行数据。如果超过一行数据,那么就要使用显式游标(对游标的讨论我们将
    在后面进行),INTO子句中要有与SELECT子句中相同列数量的变量。INTO子句中也可以是记录变量。

    %TYPE属性

      在PL/SQL中可以将变量和常量声明为内建或用户定义的数据类型,以引用一个列名,同时继承他的数据类
    型和大小。这种动态赋值方法是非常有用的,比如变量引用的列的数据类型和大小改变了,如果使用了%TYPE,
    那么用户就不必修改代码,否则就必须修改代码。

    例:

      v_empno SCOTT.EMP.EMPNO%TYPE;
      v_salary EMP.SALARY%TYPE;

      不但列名可以使用%TYPE,而且变量、游标、记录,或声明的常量都可以使用%TYPE。这对于定义相同数据类
    型的变量非常有用。

      DELCARE
       V_A NUMBER(5):=10;
      V_B V_A%TYPE:=15;
      V_C V_A%TYPE;
      BEGIN
      DBMS_OUTPUT.PUT_LINE
      ('V_A='||V_A||'V_B='||V_B||'V_C='||V_C);
      END
      SQL>/
      V_A=10 V_B=15 V_C=
      PL/SQL procedure successfully completed.
      SQL>

    其他DML语句

    其它操作数据的DML语句是:INSERT、UPDATE、DELETE和LOCK TABLE,这些语句在PL/SQL中的语法与在SQL中
    的语法相同。我们在前面已经讨

    论过DML语句的使用这里就不再重复了。在DML语句中可以使用任何在DECLARE部分声明的变量,如果是嵌套
    块,那么要注意变量的作用范围。

    例:

     1 CREATE OR REPLACE PROCEDURE FIRE_EMPLOYEE (pempno in number)
     2   AS
     3   v_ename EMP.ENAME%TYPE;
     4   BEGIN
     5   SELECT ename INTO v_ename
     6   FROM emp
     7   WHERE empno=p_empno;
     8   INSERT INTO FORMER_EMP(EMPNO,ENAME)
     9   VALUES (p_empno,v_ename);
    10   DELETE FROM emp
    11   WHERE empno=p_empno;
    12   UPDATE former_emp
    13   SET date_deleted=SYSDATE
    14   WHERE empno=p_empno;
    15   EXCEPTION
    16   WHEN NO_DATA_FOUND THEN
    17   DBMS_OUTPUT.PUT_LINE('Employee Number Not Found!');
    18   END

      DML语句的结果

    当执行一条DML语句后,DML语句的结果保存在四个游标属性中,这些属性用于控制程序流程或者了解程序
    的状态。当运行DML语句时,PL/SQL打开一个内建游标并处理结果,游标是维护查询结果的内存中的一个区域,
    游标在运行DML语句时打开,完成后关闭。隐式游标只使用SQL%FOUND,

    SQL%NOTFOUND,SQL%ROWCOUNT三个属性.SQL%FOUND,SQL%NOTFOUND是布尔值,SQL%ROWCOUNT是整数值。

    SQL%FOUND和SQL%NOTFOUND

    在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性值将是:

      . TRUE :INSERT
      . TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE.
      . TRUE :SELECT INTO至少返回一行

    当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE。

    SQL%ROWCOUNT

    在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT INTO语句,如果执行成功
    ,SQL%ROWCOUNT的值为1,如果没有成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND.

    SQL%ISOPEN

    SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE, 如果游标关闭,则为FALSE.对于隐式游标而言SQL%
    ISOPEN总是FALSE,这是因为隐式游

    标在DML语句执行时打开,结束时就立即关闭。

    事务控制语句

    事务是一个工作的逻辑单元可以包括一个或多个DML语句,事物控制帮助用户保证数据的一致性。如果事务控制逻辑单元中的任何一个DML
    语句失败,那么整个事务都将回滚,在PL/SQL中用户可以明确地使用COMMIT、ROLLBACK、SAVEPOINT以及
    SET TRANSACTION语句。

    COMMIT语句终止事务,永久保存数据库的变化,同时释放所有LOCK,ROLLBACK终止现行事务释放所有LOCK,
    但不保存数据库的任何变化,SAVEPOI

    NT用于设置中间点,当事务调用过多的数据库操作时,中间点是非常有用的,SET TRANSACTION用于设置事
    务属性,比如read-write和隔离级等。

    显式游标

    查询返回结果超过一行时,就需要一个显式游标,此时用户不能使用select into语句。PL/SQL管理隐式
    游标,当查询开始时隐式游标打开,查询结束时隐式游标自动关闭。显式游标在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取数据,关闭。

    使用游标

    这里要做一个声明,我们所说的游标通常是指显式游标,因此从现在起没有特别指明的情况,我们所说的
    游标都是指显式游标。要在程序中使用游标,必须首先声明游标。

    声明游标

    语法:

    CURSOR cursor_name IS select_statement;

    在PL/SQL中游标名是一个未声明变量,不能给游标名赋值或用于表达式中。

    例:

      
    DELCARE
      CURSOR C_EMP IS SELECT empno,ename,salary
      FROM emp
      WHERE salary>2000
      ORDER BY ename;
      ........
      BEGIN

      在游标定义中SELECT语句中不一定非要表可以是视图,也可以从多个表或视图中选择的列,甚至可以使用*
    来选择所有的列 。

    打开游标

    使用游标中的值之前应该首先打开游标,打开游标初始化查询处理。打开游标的语法是:

      OPEN cursor_name

     cursor_name是在声明部分定义的游标名。

    例:

    OPEN C_EMP;

      关闭游标

    语法:

     CLOSE cursor_name

    例:

    CLOSE C_EMP;

    从游标提取数据

    从游标得到一行数据使用FETCH命令。每一次提取数据后,游标都指向结果集的下一行。语法如下:

    FETCH cursor_name INTO variable[,variable,...]

    对于SELECT定义的游标的每一列,FETCH变量列表都应该有一个变量与之相对应,变量的类型也要相同。

    例:

     1 SET SERVERIUTPUT ON
     2   DECLARE
     3   v_ename EMP.ENAME%TYPE;
     4   v_salary EMP.SALARY%TYPE;
     5   CURSOR c_emp IS SELECT ename,salary FROM emp;
     6   BEGIN
     7   OPEN c_emp;
     8   FETCH c_emp INTO v_ename,v_salary;
     9 DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
    10   FETCH c_emp INTO v_ename,v_salary;
    11   DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
    12   FETCH c_emp INTO v_ename,v_salary;
    13   DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
    14   CLOSE c_emp;
    15   END

    这段代码无疑是非常麻烦的,如果有多行返回结果,可以使用循环并用游标属性为结束循环的条件,以这
    种方式提取数据,程序的可读性和简洁性都大为提高,下面我们使用循环重新写上面的程序: 

     1 SET SERVERIUTPUT ON
     2   DECLARE
     3   v_ename EMP.ENAME%TYPE;
     4   v_salary EMP.SALARY%TYPE;
     5   CURSOR c_emp IS SELECT ename,salary FROM emp;
     6   BEGIN
     7   OPEN c_emp;
     8   LOOP
     9   FETCH c_emp INTO v_ename,v_salary;
    10   EXIT WHEN c_emp%NOTFOUND;
    11   DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
    12   END

      记录变量

    定义一个记录变量使用TYPE命令和%ROWTYPE,关于%ROWsTYPE的更多信息请参阅相关资料。

    记录变量用于从游标中提取数据行,当游标选择很多列的时候,那么使用记录比为每列声明一个变量要方
    便得多。

    当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时,如果要选择表中所有列,那么在SELECT子句
    中使用*比将所有列名列出来要安全得多。

    例:

     1 SET SERVERIUTPUT ON
     2   DECLARE
     3   R_emp EMP%ROWTYPE;
     4   CURSOR c_emp IS SELECT * FROM emp;
     5   BEGIN
     6   OPEN c_emp;
     7   LOOP
     8   FETCH c_emp INTO r_emp;
     9   EXIT WHEN c_emp%NOTFOUND;
    10   DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
    11   END LOOP;
    12   CLOSE c_emp;
    13   END;

    %ROWTYPE也可以用游标名来定义,这样的话就必须要首先声明游标:

    SET SERVERIUTPUT ON
      DECLARE
      CURSOR c_emp IS SELECT ename,salary FROM emp;
      R_emp c_emp%ROWTYPE;
      BEGIN
      OPEN c_emp;
      LOOP
      FETCH c_emp INTO r_emp;
      EXIT WHEN c_emp%NOTFOUND;
      DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
      END LOOP;
      CLOSE c_emp;
      END;

    带参数的游标

    与存储过程和函数相似,可以将参数传递给游标并在查询中使用。这对于处理在某种条件下打开游标的情
    况非常有用。它的语法如下:

    CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;

    定义参数的语法如下:

    Parameter_name [IN] data_type[{:=|DEFAULT} value]

    与存储过程不同的是,游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。

    另外可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。

    在打开游标时给参数赋值,语法如下:

    OPEN cursor_name[value[,value]....];

    参数值可以是文字或变量。

    例:

     1 DECALRE
     2   CURSOR c_dept IS SELECT * FROM dept ORDER BY deptno;
     3   CURSOR c_emp (p_dept VARACHAR2) IS
     4   SELECT ename,salary
     5   FROM emp
     6   WHERE deptno=p_dept
     7   ORDER BY ename
     8   r_dept DEPT%ROWTYPE;
     9   v_ename EMP.ENAME%TYPE;
    10   v_salary EMP.SALARY%TYPE;
    11   v_tot_salary EMP.SALARY%TYPE;
    12   BEGIN
    13   OPEN c_dept;
    14   LOOP
    15   FETCH c_dept INTO r_dept;
    16   EXIT WHEN c_dept%NOTFOUND;
    17   DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
    18   v_tot_salary:=0;
    19   OPEN c_emp(r_dept.deptno);
    20   LOOP
    21   FETCH c_emp INTO v_ename,v_salary;
    22   EXIT WHEN c_emp%NOTFOUND;
    23   DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
    24   v_tot_salary:=v_tot_salary+v_salary;
    25   END LOOP;
    26   CLOSE c_emp;
    27   DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
    28   END LOOP;
    29   CLOSE c_dept;
    30   END;

      游标FOR循环

    在大多数时候我们在设计程序的时候都遵循下面的步骤:

    1、打开游标
    2、开始循环
    3、从游标中取值
    4、检查那一行被返回
    5、处理
    6、关闭循环
    7、关闭游标

    可以简单的把这一类代码称为游标用于循环。但还有一种循环与这种类型不相同,这就是FOR循环,用于
    FOR循环的游标按照正常的声明方式声明,它的优点在于不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。

    游标FOR循环的语法如下:

      FOR record_name IN
      (corsor_name[(parameter[,parameter]...)]
      | (query_difinition)
      LOOP
      statements
      END LOOP;

      下面我们用for循环重写上面的例子:

     1 DECALRE
     2   CURSOR c_dept IS SELECT deptno,dname FROM dept ORDER BY deptno;
     3   CURSOR c_emp (p_dept VARACHAR2) IS
     4   SELECT ename,salary
     5   FROM emp
     6   WHERE deptno=p_dept
     7   ORDER BY ename
     8   v_tot_salary EMP.SALARY%TYPE;
     9 BEGIN
    10   FOR r_dept IN c_dept LOOP
    11   DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
    12   v_tot_salary:=0;
    13   FOR r_emp IN c_emp(r_dept.deptno) LOOP
    14   DBMS_OUTPUT.PUT_LINE('Name:' || v_ename || 'salary:' || v_salary);
    15   v_tot_salary:=v_tot_salary+v_salary;
    16   END LOOP;
    17   DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
    18   END LOOP;
    19   END;

      在游标FOR循环中使用查询

    在游标FOR循环中可以定义查询,由于没有显式声明所以游标没有名字,记录名通过游标查询来定义。

     1  DECALRE
     2   v_tot_salary EMP.SALARY%TYPE;
     3   BEGIN
     4   FOR r_dept IN (SELECT deptno,dname FROM dept ORDER BY deptno) LOOP
     5   DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
     6   v_tot_salary:=0;
     7   FOR r_emp IN (SELECT ename,salary
     8   FROM emp
     9   WHERE deptno=p_dept
    10   ORDER BY ename) LOOP
    11   DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
    12   v_tot_salary:=v_tot_salary+v_salary;
    13   END LOOP;
    14   DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
    15   END LOOP;
    16   END;

      游标中的子查询

      语法如下:

      CURSOR C1 IS SELECT * FROM emp
      WHERE deptno NOT IN (SELECT deptno
      FROM dept
      WHERE dname!='ACCOUNTING');

      可以看出与SQL中的子查询没有什么区别。

      游标中的更新和删除

      在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行。显式游标只有在需要获得多行数据的情
    况下使用。PL/SQL提供了仅仅使  用游标就可以执行删除或更新记录的方法。
      UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的
    数据。要使用这个方法,在声明游标  时必须使用FOR UPDATE子串,当对话使用FOR UPDATE子串打开一个游标时,所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,其
      他对象只能查询这些数据行,不能进行UPDATE、DELETE或SELECT...FOR            UPDATE操作。

    语法:

      FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
      [nowait]

      在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,那么所有表中选择的数据行都将被锁定。
    如果这些数据行已经被其他会话锁定,那么正常情况下ORACLE将等待,直到数据行解锁。

      在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下:

      WHERE{CURRENT OF cursor_name|search_condition}

      例:

     1 DELCARE
     2   CURSOR c1 IS SELECT empno,salary
     3   FROM emp
     4   WHERE comm IS NULL
     5   FOR UPDATE OF comm;
     6   v_comm NUMBER(10,2);
     7   BEGIN
     8   FOR r1 IN c1 LOOP
     9   IF r1.salary<500 THEN
    10   v_comm:=r1.salary*0.25;
    11   ELSEIF r1.salary<1000 THEN
    12   v_comm:=r1.salary*0.20;
    13   ELSEIF r1.salary<3000 THEN
    14   v_comm:=r1.salary*0.15;
    15   ELSE
    16   v_comm:=r1.salary*0.12;
    17   END IF;
    18   UPDATE emp;
    19   SET comm=v_comm
    20   WHERE CURRENT OF c1l;
    21   END LOOP;
    22   END
     -声明游标
    --宗地表的调查日期LANDINFO_RESEARCHDATE
    --复制到流程表的权属调查时间FLOW_REASEARCHTIME
     1 DECLARE 
     2 cursor cur_sel_all is select LANDINFO_RESEARCHDATE,LANDINFO_LANDNO from t_leoa_landinfo; --定义游标
     3    l_date t_leoa_landinfo.landinfo_researchdate%type; --声明变量分别保存t_leoa_landinfo的各列
     4    l_landNo t_leoa_landinfo.landinfo_landno%type; 
     5 begin
     6 open cur_sel_all;
     7   loop                 --循环取数,并将游标数据填充到返回纪录集合中
     8    fetch cur_sel_all into l_date,l_landNo;
     9    exit when cur_sel_all%NOTFOUND; --循环退出条件
    10    if cur_sel_all%FOUND then --获取数据 
    11     update T_LEOA_BOOKFLOW t2 set FLOW_REASEARCHTIME = l_date where l_landNo = t2.landinfo_landno; 
    12    end if;
    13   end loop;
    14 close cur_sel_all;
    15 end;

    下面再分享一下另外一则游标使用方法的代码,具体如下:

     1 -- 声明游标;CURSOR cursor_name IS select_statement
     2 --For 循环游标
     3 --(1)定义游标
     4 --(2)定义游标变量
     5 --(3)使用for循环来使用这个游标
     6 declare
     7     --类型定义
     8     cursor c_job
     9     is
    10     select empno,ename,job,sal
    11     from emp
    12     where job='MANAGER';
    13     --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型
    14     c_row c_job%rowtype;
    15 begin
    16     for c_row in c_job loop
    17      dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
    18     end loop;
    19 end;
    20 --Fetch游标
    21 --使用的时候必须要明确的打开和关闭
    22 declare 
    23     --类型定义
    24     cursor c_job
    25     is
    26     select empno,ename,job,sal
    27     from emp
    28     where job='MANAGER';
    29     --定义一个游标变量
    30     c_row c_job%rowtype;
    31 begin
    32     open c_job;
    33      loop
    34       --提取一行数据到c_row
    35       fetch c_job into c_row;
    36       --判读是否提取到值,没取到值就退出
    37       --取到值c_job%notfound 是false 
    38       --取不到值c_job%notfound 是true
    39       exit when c_job%notfound;
    40       dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
    41      end loop;
    42     --关闭游标
    43    close c_job;
    44 end;
     1 --1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。
     2     begin
     3      update emp set ENAME='ALEARK' WHERE EMPNO=7469;
     4      if sql%isopen then
     5       dbms_output.put_line('Openging');
     6       else
     7        dbms_output.put_line('closing');
     8        end if;
     9      if sql%found then
    10       dbms_output.put_line('游标指向了有效行');--判断游标是否指向有效行
    11       else
    12        dbms_output.put_line('Sorry');
    13        end if;
    14        if sql%notfound then
    15         dbms_output.put_line('Also Sorry');
    16         else
    17          dbms_output.put_line('Haha');
    18          end if;
    19           dbms_output.put_line(sql%rowcount);
    20           exception 
    21            when no_data_found then
    22             dbms_output.put_line('Sorry No data');
    23             when too_many_rows then
    24              dbms_output.put_line('Too Many rows');
    25              end;
    26 declare
    27     empNumber emp.EMPNO%TYPE;
    28     empName emp.ENAME%TYPE;
    29     begin
    30      if sql%isopen then
    31       dbms_output.put_line('Cursor is opinging');
    32       else
    33        dbms_output.put_line('Cursor is Close');
    34        end if;
    35        if sql%notfound then
    36         dbms_output.put_line('No Value');
    37         else
    38          dbms_output.put_line(empNumber);
    39          end if;
    40          dbms_output.put_line(sql%rowcount);
    41          dbms_output.put_line('-------------');
    42          select EMPNO,ENAME into empNumber,empName from emp where EMPNO=7499;
    43          dbms_output.put_line(sql%rowcount);
    44         if sql%isopen then
    45         dbms_output.put_line('Cursor is opinging');
    46         else
    47         dbms_output.put_line('Cursor is Closing');
    48         end if;
    49          if sql%notfound then
    50          dbms_output.put_line('No Value');
    51          else
    52          dbms_output.put_line(empNumber);
    53          end if;
    54          exception 
    55           when no_data_found then
    56            dbms_output.put_line('No Value');
    57            when too_many_rows then
    58             dbms_output.put_line('too many rows');
    59             end;
    --2,使用游标和loop循环来显示所有部门的名称
    --游标声明
    declare 
        cursor csr_dept
        is
        --select语句
        select DNAME
        from Depth;
        --指定行指针,这句话应该是指定和csr_dept行类型相同的变量
        row_dept csr_dept%rowtype;
    begin
        --for循环
        for row_dept in csr_dept loop
          dbms_output.put_line('部门名称:'||row_dept.DNAME);
        end loop;
    end;
     1 --3,使用游标和while循环来显示所有部门的的地理位置(用%found属性)
     2 declare
     3     --游标声明
     4     cursor csr_TestWhile
     5     is
     6     --select语句
     7     select LOC
     8     from Depth;
     9     --指定行指针
    10     row_loc csr_TestWhile%rowtype;
    11 begin
    12  --打开游标
    13     open csr_TestWhile;
    14     --给第一行喂数据
    15     fetch csr_TestWhile into row_loc;
    16     --测试是否有数据,并执行循环
    17      while csr_TestWhile%found loop
    18       dbms_output.put_line('部门地点:'||row_loc.LOC);
    19       --给下一行喂数据
    20       fetch csr_TestWhile into row_loc;
    21      end loop;
    22     close csr_TestWhile;
    23 end; 
    24 select * from emp
      1 --4,接收用户输入的部门编号,用for循环和游标,打印出此部门的所有雇员的所有信息(使用循环游标)
      2 --CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
      3 --定义参数的语法如下:Parameter_name [IN] data_type[{:=|DEFAULT} value] 
      4 declare 
      5    CURSOR 
      6    c_dept(p_deptNo number)
      7    is
      8    select * from emp where emp.depno=p_deptNo;
      9    r_emp emp%rowtype;
     10 begin
     11     for r_emp in c_dept(20) loop
     12       dbms_output.put_line('员工号:'||r_emp.EMPNO||'员工名:'||r_emp.ENAME||'工资:'||r_emp.SAL);
     13     end loop;
     14 end;
     15 select * from emp  
     16 --5:向游标传递一个工种,显示此工种的所有雇员的所有信息(使用参数游标)
     17 declare 
     18     cursor
     19     c_job(p_job nvarchar2)
     20     is 
     21     select * from emp where JOB=p_job;
     22     r_job emp%rowtype;
     23 begin 
     24     for r_job in c_job('CLERK') loop
     25       dbms_output.put_line('员工号'||r_job.EMPNO||' '||'员工姓名'||r_job.ENAME);
     26     end loop;
     27 end;
     28 SELECT * FROM EMP
     29 --6:用更新游标来为雇员加佣金:(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来 
     30 --http://zheng12tian.iteye.com/blog/815770 
     31     create table emp1 as select * from emp;
     32 declare
     33     cursor
     34     csr_Update
     35     is
     36     select * from emp1 for update OF SAL;
     37     empInfo csr_Update%rowtype;
     38     saleInfo emp1.SAL%TYPE;
     39 begin
     40   FOR empInfo IN csr_Update LOOP
     41    IF empInfo.SAL<1500 THEN
     42     saleInfo:=empInfo.SAL*1.2;
     43     elsif empInfo.SAL<2000 THEN
     44     saleInfo:=empInfo.SAL*1.5;
     45     elsif empInfo.SAL<3000 THEN
     46     saleInfo:=empInfo.SAL*2;
     47    END IF;
     48    UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update;
     49    END LOOP;
     50 END;
     51 --7:编写一个PL/SQL程序块,对名字以‘A'或‘S'开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作)
     52 declare 
     53    cursor
     54    csr_AddSal
     55    is
     56    select * from emp1 where ENAME LIKE 'A%' OR ENAME LIKE 'S%' for update OF SAL;
     57    r_AddSal csr_AddSal%rowtype;
     58    saleInfo emp1.SAL%TYPE;
     59 begin
     60    for r_AddSal in csr_AddSal loop
     61      dbms_output.put_line(r_AddSal.ENAME||'原来的工资:'||r_AddSal.SAL);
     62      saleInfo:=r_AddSal.SAL*1.1;
     63      UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;
     64    end loop;
     65 end;
     66 --8:编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500
     67 declare
     68    cursor
     69      csr_AddComm(p_job nvarchar2)
     70    is
     71      select * from emp1 where  JOB=p_job FOR UPDATE OF COMM;
     72    r_AddComm emp1%rowtype;
     73    commInfo emp1.comm%type;
     74 begin
     75   for r_AddComm in csr_AddComm('SALESMAN') LOOP
     76     commInfo:=r_AddComm.COMM+500;
     77      UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm;
     78   END LOOP;
     79 END;
     80 --9:编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老)
     81 --(提示:可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。)
     82 declare
     83   cursor crs_testComput
     84   is
     85   select * from emp1 order by HIREDATE asc;
     86   --计数器
     87   top_two number:=2;
     88   r_testComput crs_testComput%rowtype;
     89 begin
     90   open crs_testComput;
     91     FETCH crs_testComput INTO r_testComput;
     92      while top_two>0 loop
     93        dbms_output.put_line('员工姓名:'||r_testComput.ENAME||' 工作时间:'||r_testComput.HIREDATE);
     94        --计速器减一
     95        top_two:=top_two-1;
     96        FETCH crs_testComput INTO r_testComput;
     97       end loop;
     98    close crs_testComput;
     99 end;
    100 --10:编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪,
    101 --如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来) 
    102 declare
    103   cursor
    104     crs_UpadateSal
    105   is
    106     select * from emp1 for update of SAL;
    107     r_UpdateSal crs_UpadateSal%rowtype;
    108     salAdd emp1.sal%type;
    109     salInfo emp1.sal%type;
    110 begin
    111     for r_UpdateSal in crs_UpadateSal loop
    112       salAdd:= r_UpdateSal.SAL*0.2;
    113       if salAdd>300 then
    114        salInfo:=r_UpdateSal.SAL;
    115        dbms_output.put_line(r_UpdateSal.ENAME||': 加薪失败。'||'薪水维持在:'||r_UpdateSal.SAL);
    116        else 
    117        salInfo:=r_UpdateSal.SAL+salAdd;
    118        dbms_output.put_line(r_UpdateSal.ENAME||': 加薪成功.'||'薪水变为:'||salInfo);
    119       end if;
    120       update emp1 set SAL=salInfo where current of crs_UpadateSal;
    121     end loop;
    122 end;
    123 --11:将每位员工工作了多少年零多少月零多少天输出出来  
    124 --近似
    125  --CEIL(n)函数:取大于等于数值n的最小整数
    126  --FLOOR(n)函数:取小于等于数值n的最大整数
    127  --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml
    128 declare
    129  cursor
    130   crs_WorkDay
    131   is
    132   select ENAME,HIREDATE, trunc(months_between(sysdate, hiredate) / 12) AS SPANDYEARS,
    133     trunc(mod(months_between(sysdate, hiredate), 12)) AS months,
    134     trunc(mod(mod(sysdate - hiredate, 365), 12)) as days
    135   from emp1;
    136  r_WorkDay crs_WorkDay%rowtype;
    137 begin
    138   for  r_WorkDay in crs_WorkDay loop
    139   dbms_output.put_line(r_WorkDay.ENAME||'已经工作了'||r_WorkDay.SPANDYEARS||'年,零'||r_WorkDay.months||'月,零'||r_WorkDay.days||'');
    140   end loop;
    141 end;
    142 --12:输入部门编号,按照下列加薪比例执行(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来
    143 -- deptno raise(%)
    144 -- 10   5%
    145 -- 20   10%
    146 -- 30   15%
    147 -- 40   20%
    148 -- 加薪比例以现有的sal为标准
    149 --CASE expr WHEN comparison_expr THEN return_expr
    150 --[, WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END
    151 declare
    152    cursor
    153      crs_caseTest
    154      is
    155      select * from emp1 for update of SAL;
    156      r_caseTest crs_caseTest%rowtype;
    157      salInfo emp1.sal%type;
    158    begin
    159      for r_caseTest in crs_caseTest loop
    160      case 
    161       when r_caseTest.DEPNO=10
    162       THEN salInfo:=r_caseTest.SAL*1.05;
    163       when r_caseTest.DEPNO=20
    164       THEN salInfo:=r_caseTest.SAL*1.1;
    165       when r_caseTest.DEPNO=30
    166       THEN salInfo:=r_caseTest.SAL*1.15;
    167       when r_caseTest.DEPNO=40
    168       THEN salInfo:=r_caseTest.SAL*1.2;
    169      end case;
    170      update emp1 set SAL=salInfo where current of crs_caseTest;
    171     end loop;
    172 end;
    173 --13:对每位员工的薪水进行判断,如果该员工薪水高于其所在部门的平均薪水,则将其薪水减50元,输出更新前后的薪水,员工姓名,所在部门编号。
    174 --AVG([distinct|all] expr) over (analytic_clause)
    175 ---作用:
    176 --按照analytic_clause中的规则求分组平均值。
    177  --分析函数语法:
    178  --FUNCTION_NAME(<argument>,<argument>...)
    179  --OVER
    180  --(<Partition-Clause><Order-by-Clause><Windowing Clause>)
    181    --PARTITION子句
    182    --按照表达式分区(就是分组),如果省略了分区子句,则全部的结果集被看作是一个单一的组
    183    select * from emp1
    184 DECLARE
    185    CURSOR 
    186    crs_testAvg
    187    IS
    188    select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG
    189    FROM EMP1 for update of SAL;
    190    r_testAvg crs_testAvg%rowtype;
    191    salInfo emp1.sal%type;
    192    begin
    193    for r_testAvg in crs_testAvg loop
    194    if r_testAvg.SAL>r_testAvg.DEP_AVG then
    195    salInfo:=r_testAvg.SAL-50;
    196    end if;
    197    update emp1 set SAL=salInfo where current of crs_testAvg;
    198    end loop;
    199 end;
  • 相关阅读:
    一个很实用的css3兼容工具很多属性可以兼容到IE6
    html5 canvas 填充渐变形状
    找到任何形状的中心-总结篇
    html canvas非正方旋转和缩放...写的大多是正方的有人表示一直看正方的看厌了
    把jQuery的类、插件封装成seajs的模块的方法
    那些年实用但被我忘掉javascript属性.onresize
    总有一些实用javascript的元素被人遗忘在角落-slice
    jquery(入门篇)无缝滚动
    html5 canvas旋转+缩放
    今天看到这篇新闻之后,决定休息一下咯
  • 原文地址:https://www.cnblogs.com/yanjie-java/p/9473117.html
Copyright © 2020-2023  润新知