Liny_@NotePad

沉迷ACG中

PL/SQL课堂练习(匿名块)

YOYO posted @ 2009年3月15日 22:48 in 【数据库】 with tags PL/SQL 匿名块 oracle 练习 , 4131 阅读

1、普通变量声明
 1)、声明3个变量:full_name varchar2(20),salary number(9,2),fdate date
 2)、用Select into语句从employees表为上面3个变量赋值,条件是rownum <= &_rownum
 3)、用DBMS_OUTPUT.PUT_LINE()打印三个变量值,结果如:Mickel.Jordon 's salary is $4680, Joined in 1987-07-12
 4)、另外声明常量PI,NUMBER(2,7)=3.1415926,声明变量flag BOOLEAN,默认值=FALSE,声明变量age NUMBER,无默认值
 5)、打印上述变量

  1.  
  2.    full_name VARCHAR2(20);
  3.    salary NUMBER(9,2);
  4.    fdate DATE;
  5.    pi CONSTANT NUMBER(8,7) := 3.1415926;
  6.    flag BOOLEAN := FALSE;
  7.    age NUMBER;
  8.  
  9.  
  10.    SELECT first_name||'.'||last_name, salary, hire_date
  11.    INTO full_name, salary, fdate
  12.    FROM employees
  13.    WHERE ROWNUM <= &_rownum;
  14.  
  15.    DBMS_OUTPUT.PUT_LINE(full_name||' ''s salary IS $'||salary||', Joined in '||to_char(fdate,'yyyy-MM-dd'));
  16.  
  17.    DBMS_OUTPUT.PUT_LINE('pi:'||pi);
  18.  
  19.    IF flag THEN
  20.       DBMS_OUTPUT.PUT_LINE('true');
  21.    ELSE
  22.       DBMS_OUTPUT.PUT_LINE('false');
  23.    END IF;
  24.  
  25.    DBMS_OUTPUT.PUT_LINE('age:'||age);
  26.  


2、游标使用
 2.1  静态游标定义
 
 1)、声明3个变量full_name varchar2(20),salary number(9,2),fdate date
 2)、声明一个静态游标,取出3个对应上面变量的值
 3)、打开游标
 4)、循环取值打印,格式如上题(可用for循环 和 loop exit循环分别实现)
 5)、关闭游标

  1. ----用 LOOP EXIT循环实现
  2.  
  3.    TYPE RECORDTYPE IS RECORD(
  4.       full_name VARCHAR2(20),
  5.       salary NUMBER(9,2),
  6.       fdate DATE
  7.    );
  8.    tmp RECORDTYPE;
  9.    CURSOR my_cur IS
  10.       SELECT first_name||''''||last_name, salary, hire_date
  11.       FROM employees;
  12.  
  13.  
  14.    IF NOT my_cur%ISOPEN THEN
  15.       OPEN my_cur;
  16.    END IF;
  17.  
  18.    LOOP
  19.         FETCH my_cur INTO tmp;
  20.         DBMS_OUTPUT.PUT_LINE(tmp.full_name||' '||tmp.salary||' '||tmp.fdate);
  21.         EXIT WHEN my_cur%notfound;
  22.    END LOOP;
  23.  
  24.    CLOSE my_cur;
  25.  
  1. ----用FOR循环实现
  2.  
  3.    CURSOR my_cur IS
  4.       SELECT first_name||''''||last_name full_name, salary, hire_date fdate
  5.       FROM employees;
  6.  
  7.  
  8.    FOR emp IN my_cur LOOP
  9.         DBMS_OUTPUT.PUT_LINE(emp.full_name||', '||emp.salary||', '||emp.fdate);
  10.    END LOOP;
  11.  

 2.2  动态游标定义

 1)、声明3个变量full_name varchar2(20),salary number(9,2),fdate date
 2)、声明一个动态游标变量
 3)、动态游标赋值并打开,指向select first_name ||'.'||last_name,salary,fire_date from employees
 4)、循环取值,打印,格式如上题
 5)、关闭游标

  1.  
  2.    TYPE ref_cur_type IS REF CURSOR;
  3.    
  4.    mycur ref_cur_type;
  5.    
  6.    TYPE employee IS RECORD(
  7.         full_name VARCHAR2(20),
  8.         salary NUMBER,
  9.         fdate DATE);
  10.        
  11.    emp employee;
  12.    
  13.  
  14.    OPEN mycur FOR SELECT first_name ||'.'||last_name,salary,hire_date FROM employees;
  15.    
  16.    LOOP
  17.         FETCH mycur INTO emp;
  18.         DBMS_OUTPUT.PUT_LINE(emp.full_name||','||emp.salary||','||emp.fdate);
  19.    
  20.         EXIT WHEN mycur%notfound;
  21.    END LOOP;
  22.    
  23.    CLOSE mycur;
  24.  

3、控制结构
 3.1 IF..ELSIF ..ELSE..END IF
 编程统计Employees表的各个薪水等级的人数,输出:
       <3000:  ***人
 [3000,6000]:  ***人
 [6000,9000]:  ***人
 [9000,12000]: ***人
 >12000      : ***人

  1.   count1 NUMBER := 0 ;
  2.   count2 NUMBER := 0 ;
  3.   count3 NUMBER := 0 ;
  4.   count4 NUMBER := 0 ;
  5.   count5 NUMBER := 0 ;
  6.   salary NUMBER ;
  7.  
  8.   TYPE cur_type IS REF CURSOR;
  9.   mycur cur_type;
  10.  
  11.  
  12.   OPEN mycur FOR SELECT salary FROM employees;
  13.  
  14.   LOOP
  15.        FETCH mycur INTO salary;
  16.        
  17.        IF salary < 3000 THEN
  18.           count1 := count1 + 1;
  19.        ELSIF salary < 6000 THEN
  20.              count2 := count2 + 1;
  21.        ELSIF salary < 9000 THEN
  22.              count3 := count3 + 1;
  23.        ELSIF salary < 12000 THEN
  24.              count4 := count4 + 1;
  25.        ELSE
  26.              count5 := count5 + 1;
  27.        END IF;
  28.  
  29.        EXIT WHEN mycur%notfound;
  30.   END LOOP;
  31.  
  32.   CLOSE mycur;
  33.  
  34.   DBMS_OUTPUT.PUT_LINE('      <3000:  '|| LPAD(count1,3,' ') || '人');
  35.   DBMS_OUTPUT.PUT_LINE('[3000,6000]:  '|| LPAD(count2,3,' ') || '人');
  36.   DBMS_OUTPUT.PUT_LINE('[6000,9000]:  '|| LPAD(count3,3,' ') || '人');
  37.   DBMS_OUTPUT.PUT_LINE('[9000,12000]: '|| LPAD(count4,3,' ') || '人');
  38.   DBMS_OUTPUT.PUT_LINE('>12000      : '|| LPAD(count5,3,' ') || '人');
  39.  

 3.2 CASE..WHEN..END CASE
 为全球各个区域的每个员工调整薪水,考虑各区域的通货膨胀率不同,拟:
 1 Europe   +10%
 2 Americas  +13%
 3 Asia   +18%
 4 Middle East and Africa +5%

 请逐行按以下格式打印:
  序号  员工全名 所在区域 原薪水 调整后薪水
  1     M*.J*       Europe 1000 1100
  2     .......

  1.   no NUMBER := 0 ;
  2.  
  3.   TYPE employee IS RECORD(
  4.        full_name VARCHAR2(20),
  5.        region regions.region_name%TYPE,
  6.        salary NUMBER
  7.   );
  8.   emp employee;
  9.  
  10.   salary_new NUMBER;
  11.  
  12.   TYPE cur_type ISIS REF CURSOR;
  13.   mycur cur_type;
  14.  
  15.  
  16.   OPEN mycur FOR
  17.                 SELECT SUBSTR(first_name,1,1)||'*.'||substr(last_name,1,1)||'*', region_name, salary
  18.                 FROM employees emp, departments dept, locations loc, countries cty, regions re
  19.                 WHERE emp.department_id = dept.department_id AND dept.location_id = loc.location_id
  20.                       AND loc.country_id = cty.country_id AND cty.region_id = re.region_id;
  21.  
  22.   DBMS_OUTPUT.PUT_LINE('序号  员工全名     所在区域     原薪水 调整后薪水');
  23.  
  24.   LOOP
  25.        FETCH mycur INTO emp;
  26.        
  27.        no := no + 1;
  28.        
  29.       CASE emp.region
  30.      
  31.       WHEN 'Europe' THEN
  32.            salary_new := emp.salary * 1.1;
  33.       WHEN 'Americas' THEN
  34.            salary_new := emp.salary * 1.13;     
  35.       WHEN 'Asia' THEN
  36.            salary_new := emp.salary * 1.18;
  37.       WHEN 'Middle East and Africa' THEN
  38.            salary_new := emp.salary * 1.05;
  39.        
  40.       END CASE;
  41.      
  42.       DBMS_OUTPUT.PUT_LINE(RPAD( no, 6, ' ')||rpad(emp.full_name, 11, ' ')||rpad(emp.region,14,' ')||rpad(emp.salary,6,' ')||salary_new);
  43.  
  44.        EXIT WHEN mycur%notfound;
  45.   END LOOP;
  46.  
  47.   CLOSE mycur;
  48.  

4、异常处理
 4.1 内置异常处理
 1)、 由外部输入值作为 select * from departments where department_id = &_depid的条件
 2)、 捕获NO_DATA_FOUND异常,并在控制台输出SQLCODE 和 SQLERRM,
  并打印出“您指定的ID为?的部门不存在!”,其中问号为你在控制台上输入的数值
 3)、若输入的部门号存在,应打印出部门的具体信息

  1.  
  2.   department departments%ROWTYPE;
  3.  
  4.  
  5.   SELECT *
  6.   INTO department
  7.   FROM departments
  8.   WHERE department_id = &_depid;
  9.  
  10.   DBMS_OUTPUT.PUT_LINE( department.department_name );
  11.  
  12.  
  13.        DBMS_OUTPUT.PUT_LINE(SQLCODE||': '||SQLERRM);
  14.  

 4.2 自定义异常处理
 1)、自定义一个异常MY_EXCEPTION                   【可考虑用pragma exception_init对异常进行正式包装(EMP_NO_DEPT,-20080801)】
 2)、遍历employees 表,打印出“ 员工ID,姓名,部门名字”
 3)、如果发现一个员工没有从属部门,raise上面的自定义的异常
 4)、在Exception段处理自定义的MY_EXCEPTION,输出“****属于无组织无纪律员工!”
 5)、在Exception段处理OTHERS,输出SQLCODE 和 SQLERRM

  1.  
  2.   emp_no_dept EXCEPTION;
  3.  
  4.   PRAGMA EXCEPTION_INIT( emp_no_dept, -1989 );
  5.  
  6.   TYPE employee IS RECORD(
  7.        eno employees.employee_id%TYPE,
  8.        ename VARCHAR2(20),
  9.        deptname departments.department_name%TYPE
  10.      );
  11.   emp employee;
  12.  
  13.   CURSOR mycur IS
  14.          SELECT employee_id, first_name||'.'||last_name, department_name
  15.          FROM employees, departments
  16.          WHERE employees.department_id = departments.department_id;
  17.  
  18.  
  19.   DBMS_OUTPUT.PUT_LINE(' 员工ID   '||'       姓名    '||'      部门名字       ');
  20.  
  21.   IF NOT mycur%ISOPEN THEN
  22.      OPEN mycur;
  23.   END IF;
  24.  
  25.   LOOP
  26.  
  27.          FETCH mycur INTO emp;
  28.          
  29.          IF emp.deptname IS NULL THEN
  30.             RAISE emp_no_dept;
  31.          END IF;
  32.          
  33.          DBMS_OUTPUT.PUT_LINE( '  '|| RPAD(emp.eno,5) || ' '|| RPAD(emp.ename,20) ||' '|| emp.deptname );
  34.  
  35.          EXIT WHEN mycur%NOTFOUND;
  36.  
  37.   END LOOP;
  38.  
  39.   CLOSE mycur;
  40.  
  41.  
  42.   WHEN emp_no_dept THEN
  43.        DBMS_OUTPUT.PUT_LINE( emp.ename || '属于无组织无纪律员工!!' );
  44.  
  45.        DBMS_OUTPUT.PUT_LINE( SQLCODE || ': ' || SQLERRM );
  46.        

5、复合变量类型使用
 5.1 Record类型
  1)、定义一个Record类型(id,fullname,jobtitle,salary),并用其声明一个变量
  2)、定义游标,SQL对应上述4个值
  3)、循环取值、打印Record变量的值

  1.  
  2.    TYPE employee IS RECORD(
  3.         id employees.employee_id%TYPE,
  4.         fullname VARCHAR2(20),
  5.         jobtitle jobs.job_title%TYPE,
  6.         salary employees.salary%TYPE
  7.    );
  8.    emp employee;
  9.    
  10.    CURSOR mycur IS
  11.           SELECT employee_id, first_name||'.'||last_name, job_title, salary
  12.           FROM employees, jobs
  13.           WHERE employees.job_id = jobs.job_id;
  14.          
  15.  
  16.    IF NOT mycur%ISOPEN THEN
  17.       OPEN mycur;
  18.    END IF;
  19.    
  20.    LOOP
  21.    
  22.        FETCH mycur INTO emp;
  23.        
  24.        DBMS_OUTPUT.PUT_LINE( emp.id ||' ['||emp.jobtitle||'] '||emp.fullname||': '||emp.salary);
  25.    
  26.        EXIT WHEN mycur%NOTFOUND;
  27.    
  28.    END LOOP;
  29.    
  30.    CLOSE mycur;
  31.  

 5.2 TABLE类型
  1)、定义一个BINARY_INTEGER TABLE类型(ID,VARCHAR2(20)),并用其声明一个变量
  2)、定义游标,Select first_name|| ''.'' ||last_name name from employees
  3)、循环取值,并为Table增加元素
  4)、输出Table的几个属性:first,last,Count、Limit
  5)、遍历Table,并输出Table的所有元素
  6)、删除Table的所有元素
  7)、再次输出Table的count

  1.  
  2.    TYPE employee IS TABLE OF VARCHAR2(20)
  3.    
  4.    emp employee;
  5.          
  6.  
  7.    SELECT first_name||'.'||last_name name
  8.    BULK COLLECT INTO emp
  9.    FROM employees;
  10.    
  11.    DBMS_OUTPUT.PUT_LINE( 'FIRST: ' || emp.FIRST );
  12.    DBMS_OUTPUT.PUT_LINE( 'LAST: ' || emp.LAST );
  13.    DBMS_OUTPUT.PUT_LINE( 'COUNT: ' || emp.COUNT );
  14.    DBMS_OUTPUT.PUT_LINE( 'LIMIT: ' || emp.LIMIT );
  15.    
  16.    FOR i IN 1 .. emp.COUNT LOOP
  17.        
  18.        DBMS_OUTPUT.PUT_LINE( i || ' ' || emp(i) );
  19.        
  20.    END LOOP;
  21.    
  22.    emp.DELETE();
  23.    
  24.    DBMS_OUTPUT.PUT_LINE( 'COUNT: ' || emp.COUNT );
  25.  

5.3 使用%ROWTYPE
  1)、用%ROWTYPE类型声明一个变量
  2)、用select * into 为该变量赋值(注意返回值应是单条记录)
  3)、输出这个变量的若干列的值

  1.  
  2.    emp employees%ROWTYPE;
  3.    
  4.    CURSOR mycur IS
  5.           SELECT *
  6.           FROM employees;
  7.          
  8.  
  9.    IF NOT mycur%ISOPEN THEN
  10.       OPEN mycur;
  11.    END IF;
  12.    
  13.    LOOP
  14.    
  15.        FETCH mycur INTO emp;
  16.        
  17.        DBMS_OUTPUT.PUT_LINE( emp.employee_id ||' '||emp.first_name||'.'||emp.last_name||': '||emp.salary);
  18.    
  19.        EXIT WHEN mycur%NOTFOUND;
  20.    
  21.    END LOOP;
  22.    
  23.    CLOSE mycur;
  24.  

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter