PL/SQL经典练习2

简介: PL/SQL经典练习2

/*

                    PL/SQL编程

=========================================================
*/

--先把scott里面的表弄到test表空间里面来
CREATE TABLE EMP AS

   SELECT * FROM SCOTT.EMP;

CREATE TABLE DEPT AS

   SELECT * FROM SCOTT.DEPT;       

/*
上机1
*/
--(1)计算King所交税金

DECLARE
V_SHUIJIN NUMBER; --应交税金
V_SAL SCOTT.EMP.SAL%TYPE; --工资
C_QIZHENDIAN CONSTANT NUMBER :=3500;
BEGIN
SELECT SAL INTO V_SAL FROM SCOTT.EMP WHERE ENAME='KING';
IF (V_SAL-C_QIZHENDIAN)<=1500 THEN

  V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.03-0;

ELSIF (V_SAL-C_QIZHENDIAN)>1500 AND (V_SAL-C_QIZHENDIAN)<=4500 THEN

  V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.1-105;

ELSIF (V_SAL-C_QIZHENDIAN)>4500 AND (V_SAL-C_QIZHENDIAN)<=9000 THEN

  V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.2-555;

ELSIF (V_SAL-C_QIZHENDIAN)>9000 AND (V_SAL-C_QIZHENDIAN)<=35000 THEN

  V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.25-1005;

ELSIF (V_SAL-C_QIZHENDIAN)>35000 AND (V_SAL-C_QIZHENDIAN)<=55000 THEN

  V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.3-2755;

ELSIF (V_SAL-C_QIZHENDIAN)>55000 AND (V_SAL-C_QIZHENDIAN)<=80000 THEN

  V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.35-5505;

ELSIF (V_SAL-C_QIZHENDIAN)>80000 THEN

  V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.45-13505;

END IF;
DBMS_OUTPUT.PUT_LINE('KING所交的税金是:'||V_SHUIJIN);
END;

--(2)根据员工scott入职的时间修改发放奖金列,大于等于6年的奖金为2000,小于6年的奖金是1500
DECLARE
V_SCOTT_HIREDATE EMP.HIREDATE%TYPE; --SCOTT的入职时间
V_COMM NUMBER; --奖金
BEGIN
SELECT HIREDATE INTO V_SCOTT_HIREDATE FROM EMP WHERE ENAME='SCOTT';

      IF (SYSDATE-V_SCOTT_HIREDATE)>=365*6 THEN
         V_COMM:=2000;
      ELSE
          V_COMM:=1500;
      END IF;

--开始修改
UPDATE EMP SET COMM=V_COMM WHERE ENAME='SCOTT';

      IF  SQL%ROWCOUNT>0 THEN
        DBMS_OUTPUT.PUT_LINE('修改成功!');
      ELSE
         DBMS_OUTPUT.PUT_LINE('修改失败!');
      END IF;

END;

--(3)查询scott相应的工资级别并显示所在部门名称,薪水,和所在的级别
DECLARE

V_SCOTT_SAL EMP.SAL%TYPE;   --scott的工资
V_JIBIE NUMBER;             --级别
V_DEPTNAME  DEPT.DNAME%TYPE;    --部门名称  

BEGIN

SELECT SAL,DNAME INTO V_SCOTT_SAL,V_DEPTNAME FROM EMP E JOIN DEPT D
       ON E.DEPTNO=D.DEPTNO
       WHERE ENAME='SCOTT';
       IF V_SCOTT_SAL>700 AND V_SCOTT_SAL<=3200 THEN
          V_JIBIE:=1;    --第一级别
       ELSIF V_SCOTT_SAL>3200 AND V_SCOTT_SAL<=4400 THEN
          V_JIBIE:=2;    --第二级别
       ELSIF V_SCOTT_SAL>4400 AND V_SCOTT_SAL<=5000 THEN
          V_JIBIE:=3;    --第三级别
       ELSIF V_SCOTT_SAL>5000 AND V_SCOTT_SAL<=7000 THEN
          V_JIBIE:=4;    --第四级别
       ELSIF V_SCOTT_SAL>7000 AND V_SCOTT_SAL<=10000 THEN
          V_JIBIE:=5;    --第五级别
       END IF;
  DBMS_OUTPUT.PUT_LINE('SCOTT所在的部门是:'||V_DEPTNAME||',薪水是:'||V_SCOTT_SAL||',所在的级别是:第'||V_JIBIE||'级别');

END;
--(4)位员工scott增加工资,每次增加100,直到增加到10000为止
DECLARE

V_SCOTT_SAL EMP.SAL%TYPE;   --SCOTT的工资

BEGIN

SELECT SAL INTO V_SCOTT_SAL FROM EMP WHERE ENAME='SCOTT';
LOOP
   --增加工资
   V_SCOTT_SAL:=V_SCOTT_SAL+100;
EXIT WHEN V_SCOTT_SAL>=10000;
END LOOP;   

--修改scott的工资
UPDATE EMP SET SAL=V_SCOTT_SAL WHERE ENAME='SCOTT';
IF SQL%ROWCOUNT>0 THEN
   DBMS_OUTPUT.PUT_LINE('增加成功!');
ELSE
   DBMS_OUTPUT.PUT_LINE('增加失败!');
END IF;

END;

/*
上机2 预定义异常
公司通过emp表维护职员记录,用以接收职员编号并检索职员姓名,
*/
DECLARE

 V_ENAME VARCHAR2(4);

BEGIN

 SELECT ENAME INTO V_ENAME FROM EMP WHERE EMPNO=&EMPNO;
      DBMS_OUTPUT.PUT_LINE('已找到'||V_ENAME);

EXCEPTION

 WHEN NO_DATA_FOUND THEN
      DBMS_OUTPUT.PUT_LINE('对不起,没有该职员!');
 WHEN VALUE_ERROR THEN
      DBMS_OUTPUT.PUT_LINE('职员名称太长!');
 WHEN OTHERS THEN 
      DBMS_OUTPUT.PUT_LINE('出现其他的异常!');

END;

/*
上机3自定义异常、
||输入员工编号,工资,部门编号,
||如果部门代码是10,且工资低于10000,更新员工的工资是10000
||如果部门代码是10,工资高于10000,显示消息“工资不低于10000”
||如果部门代码不是10则不显示
*/
DECLARE

 V_EMPNO EMP.EMPNO%TYPE;        --员工编号
 V_DEPTNO EMP.DEPTNO%TYPE;      --部门编号
 V_SAL EMP.SAL%TYPE;            --工资
 V_ENAME EMP.ENAME%TYPE;        --姓名    
 V_V_EMPNO EMP.EMPNO%TYPE;      --输入员工编号
 V_V_DEPTNO EMP.DEPTNO%TYPE;    --输入部门编号
 V_V_SAL EMP.SAL%TYPE;          --输入工资
 E_ERROR_DEPTNO EXCEPTION;      --自定义异常(部门编号不是10)
 E_ERROR_EMPNO EXCEPTION;       --自定义异常(找不到该员工)
 V_COUNT NUMBER;                --声明一个记录数

BEGIN

 --输入员工编号
 V_EMPNO:=&V_V_EMPNO;
 --输入工资
 V_SAL:=&V_VSAL;
 --输入部门编号
 V_DEPTNO:=&V_V_DEPTNO;
 IF V_DEPTNO=10 THEN
    --在进行二次判断(输入员工编号)
    IF V_SAL<10000 THEN
        --判断输入的员工编号是否存在,不存在的话报异常,存在的话继续
         SELECT COUNT(*) INTO V_COUNT FROM EMP WHERE EMPNO=V_DEPTNO;
             IF V_COUNT!=1 THEN
                RAISE E_ERROR_EMPNO;   --报异常
             ELSE
                 --更新工资为1000
                 UPDATE EMP SET SAL=10000 WHERE EMPNO=V_EMPNO;
                       IF SQL%ROWCOUNT>0 THEN
                          DBMS_OUTPUT.PUT_LINE('更新成功!!!');
                       ELSE
                          DBMS_OUTPUT.PUT_LINE('更新失败!!!');
                       END IF;
             END IF;           
    
    ELSIF V_SAL>10000 THEN
        DBMS_OUTPUT.PUT_LINE('工资不低于10000!!');
    END IF;
 ELSE
    RAISE E_ERROR_DEPTNO;
 END IF;

EXCEPTION

    WHEN E_ERROR_DEPTNO THEN
         DBMS_OUTPUT.PUT_LINE('部门代码不是10!!');
    WHEN OTHERS THEN
         DBMS_OUTPUT.PUT_LINE('出现其他异常,请自行解决!!!');

END;

SELECT * FROM EMP;
DECLARE

  V_NAME EMP.ENAME%TYPE;
  E_ERROR EXCEPTION;
  V_COUNT NUMBER;   --记录数

BEGIN

  SELECT COUNT(*) INTO V_COUNT  FROM EMP WHERE EMPNO=7901;
   IF (V_COUNT=1) THEN
   DBMS_OUTPUT.PUT_LINE(V_NAME);
   ELSE
      RAISE E_ERROR;
   END IF;
  

EXCEPTION

   WHEN E_ERROR THEN
         DBMS_OUTPUT.PUT_LINE('没有记录!');
   /*when no_data_found then
         DBMS_OUTPUT.PUT_LINE('找不到!');*/
 END;

DECLARE

  V_NAME VARCHAR2(10);
  E_ERROR EXCEPTION;

BEGIN

   IF V_NAME IS NULL THEN
      RAISE E_ERROR;
   ELSE 
      DBMS_OUTPUT.PUT_LINE(V_NAME);
   END IF;
  

EXCEPTION

   WHEN E_ERROR THEN
         DBMS_OUTPUT.PUT_LINE('没有记录!');
 END;

/*
//上机4使用游标
*/

--(1)计算公司应交税金的总额
DECLARE
V_SHUIJIN NUMBER; --应交税金
V_SAL SCOTT.EMP.SAL%TYPE; --工资
V_SUM NUMBER(10):=0; --总税金
C_QIZHENDIAN CONSTANT NUMBER :=3500;
CURSOR CURSOR_SAL IS

   SELECT SAL FROM EMP;    --所有的员工的工资

BEGIN

OPEN CURSOR_SAL; 
LOOP
    FETCH CURSOR_SAL INTO V_SAL;--把所有的工资放在V_SAL里面
     EXIT WHEN CURSOR_SAL%NOTFOUND;
       IF (V_SAL-C_QIZHENDIAN)<=1500 THEN
          V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.03-0;
       ELSIF (V_SAL-C_QIZHENDIAN)>1500 AND (V_SAL-C_QIZHENDIAN)<=4500 THEN
          V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.1-105;
       ELSIF (V_SAL-C_QIZHENDIAN)>4500 AND (V_SAL-C_QIZHENDIAN)<=9000 THEN
          V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.2-555;
       ELSIF (V_SAL-C_QIZHENDIAN)>9000 AND (V_SAL-C_QIZHENDIAN)<=35000 THEN
          V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.25-1005;
       ELSIF (V_SAL-C_QIZHENDIAN)>35000 AND (V_SAL-C_QIZHENDIAN)<=55000 THEN
          V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.3-2755;
       ELSIF (V_SAL-C_QIZHENDIAN)>55000 AND (V_SAL-C_QIZHENDIAN)<=80000 THEN
          V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.35-5505;
       ELSIF (V_SAL-C_QIZHENDIAN)>80000 THEN
          V_SHUIJIN:=(V_SAL-C_QIZHENDIAN)*0.45-13505;
       END IF;
         V_SUM:=V_SUM+V_SHUIJIN;
END LOOP;  
CLOSE CURSOR_SAL;   --关闭游标
         DBMS_OUTPUT.PUT_LINE(V_SUM);

EXCEPTION

   WHEN OTHERS THEN
         DBMS_OUTPUT.PUT_LINE('出现异常!');

END;
--(2)根据员工入职时间修改所有员工发放奖金,大于6年的+2000,小于的1500+
DECLARE

 V_COMM EMP.COMM%TYPE;          --奖金
 CURSOR CURSOR_EMP_COMM IS 
        SELECT HIREDATE FROM EMP FOR UPDATE;
                       

BEGIN

 FOR CUR1 IN CURSOR_EMP_COMM LOOP
           IF (SYSDATE-CUR1.HIREDATE)>=365*6 THEN
               V_COMM:=2000;
           ELSE
               V_COMM:=1500;
           END IF;  
       --开始修改
       UPDATE EMP SET COMM=V_COMM WHERE CURRENT OF CURSOR_EMP_COMM;
             IF SQL%ROWCOUNT>0 THEN
                 DBMS_OUTPUT.PUT_LINE('更新成功!!!');
              ELSE
                  DBMS_OUTPUT.PUT_LINE('更新失败!!!');
              END IF;
 END LOOP;

EXCEPTION

 WHEN OTHERS THEN
         DBMS_OUTPUT.PUT_LINE('出现异常!');

END;
--(3)显示员工姓名,所在部门名称,薪水,所在级别
DECLARE
C_DNAME CONSTANT VARCHAR2(20):='SALES'; --销售部门
V_JIBIE NUMBER; --级别
CURSOR CURSOR_EMP IS

      SELECT ENAME,DNAME,SAL FROM EMP E
            JOIN DEPT D ON E.DEPTNO=D.DEPTNO
            WHERE DNAME=C_DNAME;                      

BEGIN

FOR C1 IN CURSOR_EMP LOOP
     IF C1.SAL>700 AND C1.SAL<=3200 THEN
          V_JIBIE:=1;    --第一级别
       ELSIF C1.SAL>3200 AND C1.SAL<=4400 THEN
          V_JIBIE:=2;    --第二级别
       ELSIF C1.SAL>4400 AND C1.SAL<=5000 THEN
          V_JIBIE:=3;    --第三级别
       ELSIF C1.SAL>5000 AND C1.SAL<=7000 THEN
          V_JIBIE:=4;    --第四级别
       ELSIF C1.SAL>7000 AND C1.SAL<=10000 THEN
          V_JIBIE:=5;    --第五级别
       ELSE
          V_JIBIE:=0;    --没有级别
       END IF;
       DBMS_OUTPUT.put_line(C1.ENAME||'在'||C1.DNAME||'部门,'||'薪水是'||C1.SAL||'在第'||V_JIBIE||'级别');
END LOOP;

EXCEPTION

WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE('出现异常!');

END;

/*
上机5 存储过程
*/
--(1)根据输入的员工编号,删除相应的员工
CREATE OR REPLACE PROCEDURE DEL_EMPNAME
(

ENO EMP.EMPNO%TYPE,        --输入员工的编号
ON_FLAG OUT NUMBER,    --执行状态,-1失败,1成功 0异常
ON_MSG OUT VARCHAR    --提示信息

)
IS

E_ERROR EXCEPTION; --异常信息

BEGIN

DELETE FROM EMP WHERE EMPNO=ENO;
IF SQL%NOTFOUND THEN
   RAISE E_ERROR;
ELSE
   ON_FLAG:=1;      --执行成功
   ON_MSG:='删除成功!';
END IF;

EXCEPTION

   WHEN E_ERROR THEN
        ON_FLAG:=0;      --执行成功
        ON_MSG:='删除失败!';
   WHEN OTHERS THEN
        ON_FLAG:=0;
         ON_MSG:='出现异常!';

END;
DROP PROCEDURE DEL_EMPNAME;
--调用存储过程
DECLARE

V_EMPNO NUMBER;
ENO NUMBER(5);
ON_FLAG NUMBER(1);
ON_MSG VARCHAR(20);

BEGIN

ENO:=&EMPNO;   --输入编号
DEL_EMPNAME(ENO,ON_FLAG,ON_MSG);
DBMS_OUTPUT.PUT_LINE(ON_FLAG);
DBMS_OUTPUT.PUT_LINE(ON_MSG);

END;

--(2)创建输出参数为薪水集合的存储过程,调用并显示所有员工的薪水

CREATE OR REPLACE PROCEDURE get_sals(
   cur_salary OUT SYS_REFCURSOR,
   on_Flag OUT number,       --执行状态
   os_Msg OUT VARCHAR2       --提示信息

AS
BEGIN
   OPEN cur_salary FOR
       SELECT empno,sal FROM employee;
   on_Flag:=1;
   os_Msg:='成功';       
EXCEPTION
   WHEN OTHERS THEN
      on_Flag:=-1;
      os_Msg:='其他错误,与管理员联系。';
END;

DECLARE
   v_empno  employee.empno%type;
   v_sal employee.sal%type;
   emp_salary SYS_REFCURSOR;
   on_Flag number(1);     --执行状态
   os_Msg VARCHAR2(200);       --提示信息    
BEGIN
   get_sals(emp_salary,on_Flag,os_Msg);
   IF on_flag=1 THEN
      LOOP
         FETCH emp_salary INTO v_empno, v_sal;
         EXIT WHEN emp_salary%notfound;
         DBMS_OUTPUT.PUT_LINE(v_empno||'的薪水是' ||v_sal);
      END LOOP;
   ELSE
      dbms_output.put_line(os_Msg);
   END IF;
   IF emp_salary%ISOPEN THEN
      CLOSE emp_salary;
   END IF;
END;

目录
相关文章
|
2月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL隐式游标:数据的“自动导游”与“轻松之旅”
【4月更文挑战第19天】Oracle PL/SQL中的隐式游标是自动管理的数据导航工具,简化编程工作,尤其适用于简单查询和DML操作。它自动处理数据访问,提供高效、简洁的代码,但不适用于复杂场景。显式游标在需要精细控制时更有优势。了解并适时使用隐式游标,能提升数据处理效率,让开发更加轻松。
|
18天前
|
SQL 存储 数据库
技术好文:SQL查询语句基本练习
技术好文:SQL查询语句基本练习
|
23天前
|
SQL 数据库 Perl
PL/SQL中执行按钮变为灰色后如何恢复【已解决】
PL/SQL中执行按钮变为灰色后如何恢复【已解决】
39 0
|
2月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标属性:数据的“导航仪”与“仪表盘”
【4月更文挑战第19天】Oracle PL/SQL游标属性如同车辆的导航仪和仪表盘,提供丰富信息和控制。 `%FOUND`和`%NOTFOUND`指示数据读取状态,`%ROWCOUNT`记录处理行数,`%ISOPEN`显示游标状态。还有`%BULK_ROWCOUNT`和`%BULK_EXCEPTIONS`增强处理灵活性。通过实例展示了如何在数据处理中利用这些属性监控和控制流程,提高效率和准确性。掌握游标属性是提升数据处理能力的关键。
|
2月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标自定义异常:数据探险家的“专属警示灯”
【4月更文挑战第19天】Oracle PL/SQL中的游标自定义异常是处理数据异常的有效工具,犹如数据探险家的警示灯。通过声明异常名(如`LOW_SALARY_EXCEPTION`)并在满足特定条件(如薪资低于阈值)时使用`RAISE`抛出异常,能灵活应对复杂业务规则。示例代码展示了如何在游标操作中定义和捕获自定义异常,提升代码可读性和维护性,确保在面对数据挑战时能及时响应。掌握自定义异常,让数据管理更从容。
|
2月前
|
SQL Oracle 安全
Oracle的PL/SQL游标异常处理:从“惊涛骇浪”到“风平浪静”
【4月更文挑战第19天】Oracle PL/SQL游标异常处理确保了在数据操作中遇到的问题得以优雅解决,如`NO_DATA_FOUND`或`TOO_MANY_ROWS`等异常。通过使用`EXCEPTION`块捕获并处理这些异常,开发者可以防止程序因游标问题而崩溃。例如,当查询无结果时,可以显示定制的错误信息而不是让程序终止。掌握游标异常处理是成为娴熟的Oracle数据管理员的关键,能保证在复杂的数据环境中稳健运行。
|
2月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL中FOR语句循环游标的奇幻之旅
【4月更文挑战第19天】在Oracle PL/SQL中,FOR语句与游标结合,提供了一种简化数据遍历的高效方法。传统游标处理涉及多个步骤,而FOR循环游标自动处理细节,使代码更简洁、易读。通过示例展示了如何使用FOR循环游标遍历员工表并打印姓名和薪资,对比传统方式,FOR语句不仅简化代码,还因内部优化提升了执行效率。推荐开发者利用这一功能提高工作效率。
|
2月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL显式游标:数据的“私人导游”与“定制之旅”
【4月更文挑战第19天】Oracle PL/SQL中的显式游标提供灵活精确的数据访问,与隐式游标不同,需手动定义、打开、获取和关闭。通过DECLARE定义游标及SQL查询,OPEN启动查询,FETCH逐行获取数据,CLOSE释放资源。显式游标适用于复杂数据处理,但应注意SQL效率、游标管理及异常处理。它是数据海洋的私人导游,助力实现业务逻辑和数据探险。
|
2月前
|
SQL 存储 Oracle
Oracle的PL/SQL游标:数据的“探秘之旅”与“寻宝图”
【4月更文挑战第19天】Oracle PL/SQL游标是数据探索的关键工具,用于逐行访问结果集。它的工作原理包括定义、打开、FETCH和关闭,允许灵活处理数据。游标有隐式和显式两种类型,适用于不同场景,且支持参数化以增强灵活性。尽管游标在数据处理中不可或缺,但过度使用可能影响性能,因此需谨慎优化。掌握游标技巧,能有效实现业务逻辑,开启数据世界的探秘之旅。
|
2月前
|
SQL Oracle 安全
Oracle的PL/SQL异常处理方法:守护数据之旅的“魔法盾”
【4月更文挑战第19天】Oracle PL/SQL的异常处理机制是保障数据安全的关键。通过预定义异常(如`NO_DATA_FOUND`)和自定义异常,开发者能优雅地管理错误。异常在子程序中抛出后会向上传播,直到被捕获,提供了一种集中处理错误的方式。理解和善用异常处理,如同手持“魔法盾”,确保程序在面对如除数为零、违反约束等挑战时,能有效保护数据的完整性和程序的稳定性。