plSql介绍
编程技术  /  houtizong 发布于 3年前   80
/* * PL/SQL 程序设计学习笔记 * 学习plSql介绍.pdf * 时间:2010-10-05*/--创建DEPT表create table DEPT( DEPTNO NUMBER(10), DNAME NVARCHAR2(255), LOC NVARCHAR2(255))delete dept;select * from dept;--插入一条记录并显示DECLARE Row_id UROWID; info VARCHAR2(40);BEGIN INSERT INTO dept VALUES (90, 'SERVICE', 'BEIJING') RETURNING rowid, dname||':'||to_char(deptno)||':'||loc INTO row_id, info; DBMS_OUTPUT.PUT_LINE('ROWID:'||row_id); DBMS_OUTPUT.PUT_LINE(info);END;--修改一条记录并显示DECLARE Row_id UROWID; info VARCHAR2(40);BEGIN UPDATE dept SET deptno=80 WHERE DNAME='SERVICE' RETURNING rowid, dname||':'||to_char(deptno)||':'||loc INTO row_id, info; DBMS_OUTPUT.PUT_LINE('ROWID:'||row_id); DBMS_OUTPUT.PUT_LINE(info);END;--删除一条记录并显示DECLARE Row_id UROWID; info VARCHAR2(40);BEGIN DELETE dept WHERE DNAME='SERVICE' RETURNING rowid, dname||':'||to_char(deptno)||':'||loc INTO row_id, info; DBMS_OUTPUT.PUT_LINE('ROWID:'||row_id); DBMS_OUTPUT.PUT_LINE(info);END;--复合类型-记录类型DECLARE TYPE test_rec IS RECORD( Code VARCHAR2(10), Name VARCHAR2(30) NOT NULL :='a book'); V_book test_rec;BEGIN V_book.code :='123'; V_book.name :='C++ Programming'; DBMS_OUTPUT.PUT_LINE(v_book.code||v_book.name);END;--复合类型-使用%TYPE--创建emp表create table emp( empno NUMBER(10), ename NVARCHAR2(255), sal NUMBER(10,2), hiredate Timestamp, comm NUMBER(10,2), job NVARCHAR2(255), deptno NUMBER(10))insert into emp(empno,ename,sal,hiredate,comm,job,deptno) values(100,'Test',30.5,sysdate,10,'president',1);insert into emp(empno,ename,sal,hiredate,comm,job,deptno) values(7788,'Test2',100.23,sysdate,10.2,'manager',2);--drop table emp;select * from emp;DECLARE--用%TYPE 类型定义与表相配的字段 TYPE t_Record IS RECORD( T_no emp.empno%TYPE, T_name emp.ename%TYPE, T_sal emp.sal%TYPE ); --声明接收数据的变量 v_emp t_Record;BEGIN SELECT empno, ename, sal INTO v_emp FROM emp WHERE empno=7788; DBMS_OUTPUT.PUT_LINE (TO_CHAR(v_emp.t_no)||v_emp.t_name||TO_CHAR(v_emp.t_sal));END;DECLARE v_empno emp.empno%TYPE :=&empno; Type r_record is record ( v_name emp.ename%TYPE, v_sal emp.sal%TYPE, v_date emp.hiredate%TYPE); Rec r_record;BEGIN SELECT ename, sal, hiredate INTO Rec FROM emp WHERE empno=v_empno; DBMS_OUTPUT.PUT_LINE(Rec.v_name||'--'||Rec.v_sal||'--'||Rec.v_date);END;--使用%ROWTYPEDECLARE v_empno emp.empno%TYPE :=&empno; rec emp%ROWTYPE;BEGIN SELECT * INTO rec FROM emp WHERE empno=v_empno; DBMS_OUTPUT.PUT_LINE('姓名:'||rec.ename||'工资:'||rec.sal||'工作时间:'||rec.hiredate);END;--以下脚本只能在sqlplus命令行中执行----start-----VARIABLE result2 NUMBER BEGIN SELECT (sal*12)+nvl(comm, 0) INTO :result2 FROM emp WHERE empno=7788; END;PRINT result2;-----end-------INDEX BY TABLESselect * from dept;insert into dept(deptno,dname,loc) values(1,'Test1','BEIJING');insert into dept(deptno,dname,loc) values(10,'Test10','SHENGZHEN');insert into dept(deptno,dname,loc) values(20,'Test20','CHANGSHA');insert into dept(deptno,dname,loc) values(30,'Test30','ZHUHAI');insert into dept(deptno,dname,loc) values(40,'Test40','SHAOYANG');DECLARE TYPE dept_table_type IS TABLE OF dept%ROWTYPE INDEX BY BINARY_INTEGER; my_dname_table dept_table_type; v_count number(2) :=4;BEGIN FOR i IN 1 .. v_count LOOP SELECT * INTO my_dname_table(i) FROM dept WHERE deptno=i*10; END LOOP; FOR i IN my_dname_table.FIRST.. my_dname_table.LAST LOOP DBMS_OUTPUT.PUT_LINE('Department number: '||my_dname_table(i).deptno); DBMS_OUTPUT.PUT_LINE('Department name: '|| my_dname_table(i).dname); END LOOP;END;--BOOLEAN 赋值DECLARE done BOOLEAN; /* the following statements are legal: */BEGIN done := FALSE; WHILE NOT done LOOP Null; END LOOP;END;SELECT * FROM EMP--数据库赋值DECLARE emp_id emp.empno%TYPE :=7788; emp_name emp.ename%TYPE; wages emp.sal%TYPE;BEGIN SELECT ename, NVL(sal,0) + NVL(comm,0) INTO emp_name, wages FROM emp WHERE empno = emp_id; Dbms_output.put_line(emp_name||'----'||to_char(wages));END;SELECT * FROM emp;insert into emp(empno,ename,sal,hiredate,comm,job,deptno) values(8,'Test3',10.23,sysdate,1.2,'manager',3);insert into emp(empno,ename,sal,hiredate,comm,job,deptno) values(12,'Test4',10.23,sysdate,1.2,'president',4);delete emp where empno = 8;delete emp where empno = 12;--变量作用范围及可见性DECLARE Emess char(80);BEGIN DECLARE V1 NUMBER(4); BEGIN SELECT empno INTO v1 FROM emp WHERE LOWER(job)='president'; DBMS_OUTPUT.PUT_LINE(V1); EXCEPTION When TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE ('More than one president'); END; DECLARE V1 NUMBER(4); BEGIN SELECT empno INTO v1 FROM emp WHERE LOWER(job)='manager'; DBMS_OUTPUT.PUT_LINE(V1); EXCEPTION When TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE ('More than one manager'); END;EXCEPTIONWhen others THEN Emess:=substr(SQLERRM,1,80); DBMS_OUTPUT.PUT_LINE (emess);END;select * from emp;/* 本例子仅是一个简单的插入,不是实际应用。*/DECLARE v_ename VARCHAR2(20) := 'Bill'; v_sal NUMBER(7,2) :=1234.56; v_deptno NUMBER(2) := 10; v_empno NUMBER(4) := 8888;BEGIN INSERT INTO emp ( empno, ename, JOB, sal, deptno , hiredate ) VALUES ( v_empno, v_ename, 'Manager', v_sal, v_deptno,TO_DATE('1954.06.09','yyyy.mm.dd') ); COMMIT;END;/* 本例子仅是一个简单的删除例子,不是实际应用。*/DECLARE v_empno number(4) := 8888;BEGIN DELETE FROM emp WHERE empno=v_empno; COMMIT;END;select * from emp;--条件语句DECLARE v_empno emp.empno%TYPE :=&empno; V_salary emp.sal%TYPE; V_comment VARCHAR2(35);BEGIN SELECT sal INTO v_salary FROM emp WHERE empno=v_empno; IF v_salary<1500 THEN V_comment:= 'Fairly less'; ELSIF v_salary <3000 THEN V_comment:= 'A little more'; ELSE V_comment:= 'Lots of salary'; END IF; DBMS_OUTPUT.PUT_LINE(V_comment);END;--CASE 表达式DECLARE V_grade char(1) := UPPER('&p_grade'); V_appraisal VARCHAR2(20);BEGIN V_appraisal := CASE v_grade WHEN 'A' THEN 'Excellent' WHEN 'B' THEN 'Very Good' WHEN 'C' THEN 'Good' ELSE 'No such grade' END; DBMS_OUTPUT.PUT_LINE('Grade:'||v_grade||' Appraisal: '|| v_appraisal);END;--简单循环DECLARE int NUMBER(2) :=0;BEGIN LOOP int := int + 1; DBMS_OUTPUT.PUT_LINE('int 的当前值为:'||int); EXIT WHEN int =10; END LOOP;END;--WHILE 循环DECLARE x NUMBER;BEGIN x:= 1; WHILE x<10 LOOP DBMS_OUTPUT.PUT_LINE('X 的当前值为:'||x); x:= x+1; END LOOP;END;--数字式循环BEGIN FOR int in 1..10 LOOP DBMS_OUTPUT.PUT_LINE('int 的当前值为: '||int); END LOOP;END;--数字式循环-循环变量自动减1BEGIN FOR int in REVERSE 1..10 LOOP DBMS_OUTPUT.PUT_LINE('int 的当前值为: '||int); END LOOP;END;CREATE TABLE temp_table(num_col NUMBER);DECLARE V_counter NUMBER := 10;BEGIN INSERT INTO temp_table(num_col)VALUES (v_counter ); FOR v_counter IN 20 .. 25 LOOP INSERT INTO temp_table (num_col ) VALUES ( v_counter ); END LOOP; INSERT INTO temp_table(num_col)VALUES (v_counter ); FOR v_counter IN REVERSE 20 .. 25 LOOP INSERT INTO temp_table (num_col ) VALUES ( v_counter ); END LOOP;END;DROP TABLE temp_table;select * from temp_table;--标号和GOTODECLARE V_counter NUMBER := 1;BEGIN LOOP DBMS_OUTPUT.PUT_LINE('V_counter 的当前值为:'||V_counter); V_counter := v_counter + 1; IF v_counter > 10 THEN GOTO l_ENDofLOOP; END IF; END LOOP;<<l_ENDofLOOP>> DBMS_OUTPUT.PUT_LINE('V_counter 的当前值为:'||V_counter);END;select * from dept;--游标参数的传递方法DECLARE DeptRec dept%ROWTYPE; Dept_name dept.dname%TYPE; Dept_loc dept.loc%TYPE;CURSOR c1 IS SELECT dname, loc FROM dept WHERE deptno <= 30;CURSOR c2(dept_no NUMBER DEFAULT 10) IS SELECT dname, loc FROM dept WHERE deptno <= dept_no;CURSOR c3(dept_no NUMBER DEFAULT 10) IS SELECT * FROM dept WHERE deptno <=dept_no;BEGIN OPEN c1; LOOP FETCH c1 INTO dept_name, dept_loc; EXIT WHEN c1%NOTFOUND; DBMS_OUTPUT.PUT_LINE(dept_name||'---'||dept_loc); END LOOP; CLOSE c1; DBMS_OUTPUT.PUT_LINE('cl closed!'); OPEN c2; LOOP FETCH c2 INTO dept_name, dept_loc; EXIT WHEN c2%NOTFOUND; DBMS_OUTPUT.PUT_LINE(dept_name||'---'||dept_loc); END LOOP; CLOSE c2; DBMS_OUTPUT.PUT_LINE('c2 closed!'); OPEN c3(dept_no =>20); LOOP FETCH c3 INTO deptrec; EXIT WHEN c3%NOTFOUND; DBMS_OUTPUT.PUT_LINE(deptrec.deptno||'---'||deptrec.dname||'---'||deptrec.loc); END LOOP; CLOSE c3; DBMS_OUTPUT.PUT_LINE('c3 closed!');END;SELECT * FROM dept WHERE deptno <=30;select * from emp;--给工资低于1200的员工增加工资50DECLARE v_empno emp.empno%TYPE; v_sal emp.sal%TYPE; CURSOR c IS SELECT empno, sal FROM emp;BEGIN OPEN c; LOOP FETCH c INTO v_empno, v_sal; EXIT WHEN C%NOTFOUND; IF v_sal<=1200 THEN UPDATE emp SET sal=sal+50 WHERE empno=v_empno; DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'工资已更新!'); END IF; DBMS_OUTPUT.PUT_LINE('记录数:'||C%ROWCOUNT); END LOOP;CLOSE c;END;--游标的FOR循环DECLARE CURSOR c_sal IS SELECT empno, ename, sal FROM emp;BEGIN --隐含打开游标 FOR v_sal IN c_sal LOOP --隐含执行一个FETCH 语句 DBMS_OUTPUT.PUT_LINE( to_char(v_sal.empno)||'---'||v_sal.ename||'---'||to_char(v_sal.sal)); --隐含监测c_sal%NOTFOUND END LOOP; --隐含关闭游标END;--当所声明的游标带有参数时,通过游标FOR 循环语句为游标传递参数DECLARE CURSOR c1(dept_no NUMBER DEFAULT 10) IS SELECT dname, loc FROM dept WHERE deptno <= dept_no;BEGIN DBMS_OUTPUT.PUT_LINE('dept_no 参数值为30:'); FOR c1_rec IN c1(30) LOOP DBMS_OUTPUT.PUT_LINE(c1_rec.dname||'---'||c1_rec.loc); END LOOP; DBMS_OUTPUT.PUT_LINE(CHR(10)||'使用默认的dept_no 参数值10:'); FOR c1_rec IN c1 LOOP DBMS_OUTPUT.PUT_LINE(c1_rec.dname||'---'||c1_rec.loc); END LOOP;END;--PL/SQL 还允许在游标FOR 循环语句中使用子查询来实现游标的功能。BEGIN FOR c1_rec IN (SELECT dname, loc FROM dept) LOOP DBMS_OUTPUT.PUT_LINE(c1_rec.dname||'---'||c1_rec.loc); END LOOP;END;--删除EMP 表中某部门的所有员工,如果该部门中已没有员工,则在DEPT 表中删除该部门DECLARE V_deptno emp.deptno%TYPE :=&p_deptno;BEGIN DELETE FROM emp WHERE deptno=v_deptno; IF SQL%NOTFOUND THEN DELETE FROM dept WHERE deptno=v_deptno; END IF;END;select * from emp;select * from dept;--从EMP表中查询某部门的员工情况,将其工资最低定为1500DECLARE V_deptno emp.deptno%TYPE :=&p_deptno; CURSOR emp_cursor IS SELECT empno, sal FROM emp WHERE deptno=v_deptno FOR UPDATE OF sal NOWAIT;BEGIN FOR emp_record IN emp_cursor LOOP IF emp_record.sal< 1500 THEN UPDATE emp SET sal=1500 WHERE CURRENT OF emp_cursor; END IF; END LOOP; --COMMIT;END;select * from emp;--预定义的异常处理-更新指定员工工资,如工资小于1500,则加100DECLARE v_empno emp.empno%TYPE :=&empno; v_sal emp.sal%TYPE;BEGIN SELECT sal INTO v_sal FROM emp WHERE empno=v_empno; IF v_sal<=1400 THEN UPDATE emp SET sal=sal+100 WHERE empno=v_empno; DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已更新!'); ELSE DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已经超过规定值!'); END IF;EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('数据库中没有编码为'||v_empno||'的员工'); WHEN TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!');END;select * from dept;--删除指定部门的记录信息,以确保该部门没有员工。INSERT INTO dept VALUES(50, 'FINANCE', 'CHICAGO');DECLARE v_deptno dept.deptno%TYPE :=&deptno; e_deptno_remaining EXCEPTION; PRAGMA EXCEPTION_INIT(e_deptno_remaining,2292); /* 2292 是违反一致性约束的错误代码*/BEGIN DELETE FROM dept WHERE deptno=v_deptno;EXCEPTION WHEN e_deptno_remainingTHEN DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!');END;select * from emp;--更新指定员工工资,增加100DECLARE v_empno emp.empno%TYPE :=&empno; no_result EXCEPTION;BEGIN UPDATE emp SET sal=sal+100 WHERE empno=v_empno; IF SQL%NOTFOUND THEN RAISE no_result; END IF;EXCEPTION WHEN no_result THEN DBMS_OUTPUT.PUT_LINE('你的数据更新语句失败了!'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!');END;--创建一个函数get_salary, 该函数检索指定部门的工资总和,其中定义了20991和20992号错误,分别处理参数为空和非法部门代码两种错误CREATE TABLE errlog(Errcode NUMBER,Errtext CHAR(40));CREATE OR REPLACE FUNCTION get_salary(p_deptno NUMBER) RETURN NUMBER AS V_sal NUMBER;BEGIN IF p_deptno IS NULL THEN RAISE_APPLICATION_ERROR(-20991,'部门代码为空'); ELSIF p_deptno<0 THEN RAISE_APPLICATION_ERROR(-20992,'无效的部门代码'); ELSE SELECT SUM(sal) INTO v_sal FROM EMP WHERE deptno=p_deptno; RETURN V_sal; END IF;END;select * from emp;select * from errlog;delete errlog;DECLARE V_salary NUMBER(7,2); V_sqlcode NUMBER; V_sqlerr VARCHAR2(512); Null_deptno EXCEPTION; Invalid_deptno EXCEPTION; PRAGMA EXCEPTION_INIT(null_deptno,-20991); PRAGMA EXCEPTION_INIT(invalid_deptno, -20992);BEGIN V_salary :=get_salary(1); DBMS_OUTPUT.PUT_LINE('1 号部门工资:'||TO_CHAR(V_salary)); BEGIN V_salary :=get_salary(-10); EXCEPTION WHEN invalid_deptno THEN V_sqlcode :=SQLCODE; V_sqlerr :=SQLERRM; INSERT INTO errlog(errcode,errtext) VALUES(v_sqlcode, v_sqlerr); COMMIT; END inner1; V_salary :=get_salary(20); DBMS_OUTPUT.PUT_LINE('20 号部门工资:'||TO_CHAR(V_salary)); BEGIN V_salary :=get_salary(NULL); END inner2; V_salary :=get_salary(30); DBMS_OUTPUT.PUT_LINE('30 号部门工资:'||TO_CHAR(V_salary)); EXCEPTION WHEN null_deptno THEN V_sqlcode :=SQLCODE; V_sqlerr :=SQLERRM; INSERT INTO errlog(errcode,errtext) VALUES(v_sqlcode, v_sqlerr); COMMIT; WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!');END outer;--将ORACLE 错误代码及其信息存入错误代码表CREATE TABLE errors(errnum NUMBER(4), errmsg VARCHAR2(100));select * from errors;DECLARE err_msg VARCHAR2(100);BEGIN /* 得到所有ORACLE 错误信息*/ FOR err_num IN -100.. 0 LOOP err_msg := SQLERRM(err_num); INSERT INTO errors VALUES(err_num, err_msg); END LOOP;END;DROP TABLE errors;--查询ORACLE 错误代码select * from emp;BEGIN INSERT INTO emp(empno,ename, hiredate, deptno) VALUES(2222, 'Jerry', SYSDATE, 20); DBMS_OUTPUT.PUT_LINE('插入数据记录成功!'); INSERT INTO emp(empno,ename, hiredate, deptno) VALUES(2222, 'Jerry', SYSDATE, 20); DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);END;--获取某部门的工资总和CREATE OR REPLACE FUNCTION get_salaryf( Dept_no NUMBER, Emp_count OUT NUMBER) RETURN NUMBER IS V_sum NUMBER;BEGIN SELECT SUM(sal), count(*) INTO V_sum, emp_count FROM emp WHERE deptno=dept_no; RETURN v_sum;EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('你需要的数据不存在!'); WHEN TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!');END get_salaryf;select * from emp;--内嵌函数的调用-第一种参数传递格式称为位置表示法--计算某部门的工资总和DECLARE V_num NUMBER; V_sum NUMBER;BEGIN V_sum := get_salaryf(3, v_num); DBMS_OUTPUT.PUT_LINE('3 号部门工资总和:'||v_sum||',人数:'||v_num);END;--内嵌函数的调用-第二种参数传递格式称为名称表示法DECLARE V_num NUMBER; V_sum NUMBER;BEGIN V_sum :=get_salaryf(emp_count=> v_num, dept_no => 3); DBMS_OUTPUT.PUT_LINE('3 号部门工资总和:'||v_sum||',人数:'||v_num);END;--内嵌函数的调用-第三种参数传递格式称为混合表示法CREATE OR REPLACE FUNCTION demo_fun( Name VARCHAR2, Age INTEGER, Sex VARCHAR2) RETURN VARCHAR2 AS V_var VARCHAR2(32);BEGIN V_var := name||':'||TO_CHAR(age)||'岁,'||sex; RETURN v_var;END;DECLARE Var VARCHAR(32);BEGIN Var := demo_fun('user1', 30, sex => '男'); DBMS_OUTPUT.PUT_LINE(var); Var := demo_fun('user2', age => 40, sex => '男'); DBMS_OUTPUT.PUT_LINE(var); Var := demo_fun('user3', sex => '女', age => 20); DBMS_OUTPUT.PUT_LINE(var);END;--参数默认值CREATE OR REPLACE FUNCTION demo_fun2( Name VARCHAR2, Age INTEGER, Sex VARCHAR2 DEFAULT '男') RETURN VARCHAR2 AS V_var VARCHAR2(32);BEGIN V_var := name||':'||TO_CHAR(age)||'岁,'||sex; RETURN v_var;END;DECLARE Var VARCHAR(32);BEGIN Var := demo_fun2('user1', 30); DBMS_OUTPUT.PUT_LINE(var); Var := demo_fun2('user2', age => 40); DBMS_OUTPUT.PUT_LINE(var); Var := demo_fun2('user3', sex => '女', age => 20); DBMS_OUTPUT.PUT_LINE(var);END;--存储过程--用户连接登记记录CREATE table logtable (userid VARCHAR2(10), logdate date);CREATE OR REPLACE PROCEDURE logexecution ISBEGIN INSERT INTO logtable (userid, logdate) VALUES (USER, SYSDATE);END;--删除指定员工记录CREATE OR REPLACE PROCEDURE DelEmp(v_empno IN emp.empno%TYPE)AS No_result EXCEPTION;BEGIN DELETE FROM emp WHERE empno=v_empno; IF SQL%NOTFOUND THEN RAISE no_result; END IF; DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'的员工已被除名!');EXCEPTION WHEN no_result THEN DBMS_OUTPUT.PUT_LINE('你需要的数据不存在!'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!');END DelEmp;--计算指定部门的工资总和,并统计其中的职工数量CREATE OR REPLACE PROCEDURE proc_demo( Dept_no NUMBER DEFAULT 10, Sal_sum OUT NUMBER, Emp_count OUT NUMBER)ISBEGIN SELECT SUM(sal), COUNT(*) INTO sal_sum, emp_count FROM emp WHERE deptno=dept_no;EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('你需要的数据不存在!'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!');END proc_demo;select * from emp;DECLARE V_num NUMBER; V_sum NUMBER(8, 2);BEGIN Proc_demo(1, v_sum, v_num); DBMS_OUTPUT.PUT_LINE('1 号部门工资总和:'||v_sum||',人数:'||v_num); Proc_demo(sal_sum=> v_sum, emp_count => v_num); DBMS_OUTPUT.PUT_LINE('10 号部门工资总和:'||v_sum||',人数:'||v_num);END;--建立本地过程,用于计算指定部门的工资总和,并统计其中的职工数量DECLARE V_num NUMBER; V_sum NUMBER(8, 2); PROCEDURE proc_demo( Dept_no NUMBER DEFAULT 10, Sal_sum OUT NUMBER, Emp_count OUT NUMBER) IS BEGIN SELECT SUM(sal), COUNT(*) INTO sal_sum, emp_count FROM emp WHERE deptno=dept_no; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('你需要的数据不存在!'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发生其它错误!'); END proc_demo;BEGIN Proc_demo(1, v_sum, v_num); DBMS_OUTPUT.PUT_LINE('1 号部门工资总和:'||v_sum||',人数:'||v_num); Proc_demo(sal_sum=> v_sum, emp_count => v_num); DBMS_OUTPUT.PUT_LINE('10 号部门工资总和:'||v_sum||',人数:'||v_num);END;--授权执行权给相关的用户或角色CREATE OR REPLACE PUBLIC SYNONYM DBMS_JOB FOR DBMS_JOB;GRANT EXECUTE ON dbms_job TO PUBLIC WITH GRANT OPTION;--与过程相关数据字典select * from USER_SOURCE;select * from ALL_SOURCE;select * from DBA_SOURCE;select * from USER_ERRORS;DESC proc_demo;desc emp;DROP PROCEDURE logexecution;select * from dept;--包的创建和应用--包定义的说明--创建的包为demo_pack, 该包中包含一个记录变量DeptRec、两个函数和一个过程CREATE OR REPLACE PACKAGE demo_pack IS DeptRec dept%ROWTYPE; V_sqlcode NUMBER; V_sqlerr VARCHAR2(2048); FUNCTION add_dept( dept_no NUMBER, dept_name VARCHAR2, location VARCHAR2) RETURN NUMBER; FUNCTION remove_dept(dept_no NUMBER) RETURN NUMBER; PROCEDURE query_dept(dept_no IN NUMBER);END demo_pack;--包主体的创建CREATE OR REPLACE PACKAGE BODY demo_pack IS Flag INTEGER; FUNCTION check_dept(dept_no NUMBER) RETURN INTEGER; FUNCTION add_dept(dept_no NUMBER, dept_name VARCHAR2, location VARCHAR2) RETURN NUMBER IS BEGIN IF check_dept(dept_no)=0 THEN INSERT INTO dept VALUES(dept_no, dept_name, location); RETURN 1; ELSE RETURN 0; END IF; EXCEPTION WHEN OTHERS THEN V_sqlcode := SQLCODE; V_sqlerr := SQLERRM; RETURN 1; END add_dept; FUNCTION remove_dept(dept_no NUMBER) RETURN NUMBER IS BEGIN V_sqlcode := 0; V_sqlerr := NULL; IF check_dept(dept_no)= 1 THEN DELETE FROM dept WHERE deptno=dept_no; RETURN 1; ELSE RETURN 0; END IF; EXCEPTION WHEN OTHERS THEN V_sqlcode := SQLCODE; V_sqlerr := SQLERRM; RETURN 1; END remove_dept; PROCEDURE query_dept(dept_no IN NUMBER) IS BEGIN IF check_dept(dept_no)=1 THEN SELECT * INTO DeptRec FROM dept WHERE deptno=dept_no; END IF; END query_dept; FUNCTION check_dept(dept_no NUMBER) RETURN INTEGER IS BEGIN SELECT COUNT(*) INTO flag FROM dept WHERE deptno=dept_no; IF flag > 0 THEN Flag := 1; END IF; RETURN flag; END check_dept; BEGIN V_sqlcode := NULL; V_sqlerr := NULL;END demo_pack;select * from dept;delete dept where deptno=90;--对包内共有元素的调用格式为:包名.元素名称DECLARE Var NUMBER;BEGIN Var := demo_pack.add_dept(90,'Administration', 'Beijing'); IF Var =-1 THEN DBMS_OUTPUT.PUT_LINE(demo_pack.v_sqlerr); ELSIF Var =0 THEN DBMS_OUTPUT.PUT_LINE('该部门记录已经存在!'); ELSE DBMS_OUTPUT.PUT_LINE('添加记录成功!'); Demo_pack.query_dept(90); DBMS_OUTPUT.PUT_LINE(demo_pack.DeptRec.deptno||'---'||demo_pack.DeptRec.dname||'---'||demo_pack.DeptRec.loc); Var := demo_pack.remove_dept(90); IF Var =-1 THEN DBMS_OUTPUT.PUT_LINE(demo_pack.v_sqlerr); ELSE DBMS_OUTPUT.PUT_LINE('删除记录成功!'); END IF; END IF;END;select * from emp;--创建包emp_packageCREATE OR REPLACE PACKAGE emp_package IS TYPE emp_table_type IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER; PROCEDURE read_emp_table(p_emp_table OUT emp_table_type);END emp_package;CREATE OR REPLACE PACKAGE BODY emp_package IS PROCEDURE read_emp_table(p_emp_table OUT emp_table_type) IS I BINARY_INTEGER := 0; BEGIN FOR emp_record IN ( SELECT * FROM emp ) LOOP P_emp_table(i) := emp_record; I := I + 1; END LOOP; END read_emp_table;END emp_package;DECLARE E_table emp_package.emp_table_type;BEGIN Emp_package.read_emp_table(e_table); FOR I IN e_table.FIRST .. e_table.LAST LOOP DBMS_OUTPUT.PUT_LINE(e_table(i).empno||'---'||e_table(i).ename); END LOOP;END;--子程序重载--PL/SQL 允许对包内子程序和本地子程序进行重载。所谓重载时指两个或多个子程序有相同--的名称,但拥有不同的参数变量、参数顺序或参数数据类型。CREATE OR REPLACE PACKAGE demo_pack1 IS DeptRec dept%ROWTYPE; V_sqlcode NUMBER; V_sqlerr VARCHAR2(2048); FUNCTION query_dept(dept_no IN NUMBER) RETURN INTEGER; FUNCTION query_dept(dept_no IN VARCHAR2) RETURN INTEGER;END demo_pack1;CREATE OR REPLACE PACKAGE BODY demo_pack1 IS FUNCTION check_dept(dept_no NUMBER) RETURN INTEGER IS Flag INTEGER; BEGIN SELECT COUNT(*) INTO flag FROM dept WHERE deptno=dept_no; IF flag > 0 THEN RETURN 1; ELSE RETURN 0; END IF; END check_dept; FUNCTION check_dept(dept_no VARCHAR2) RETURN INTEGER IS Flag INTEGER; BEGIN SELECT COUNT(*) INTO flag FROM dept WHERE deptno=dept_no; IF flag > 0 THEN RETURN 1; ELSE RETURN 0; END IF; END check_dept; FUNCTION query_dept(dept_no IN NUMBER) RETURN INTEGER IS BEGIN IF check_dept(dept_no)=1 THEN SELECT * INTO DeptRec FROM dept WHERE deptno=dept_no; RETURN 1; ELSE RETURN 0; END IF; END query_dept; FUNCTION query_dept(dept_no IN VARCHAR2) RETURN INTEGER IS BEGIN IF check_dept(dept_no)=1 THEN SELECT * INTO DeptRec FROM dept WHERE deptno=dept_no; RETURN 1; ELSE RETURN 0; END IF; END query_dept;END demo_pack1;--删除包DROP PACKAGE demo_pack1;--包的管理select * from DBA_SOURCE;select * from USER_SOURCE;select * from USER_ERRORS;select * from DBA_OBJECTS;select * from emp;select * from emp_his;insert into emp(empno,ename,sal,hiredate,comm,job,deptno) values(100,'Test',30.5,sysdate,10,'president',1);insert into emp(empno,ename,sal,hiredate,comm,job,deptno) values(7788,'Test2',100.23,sysdate,10.2,'manager',2);CREATE TABLE emp_his AS SELECT * FROM EMP WHERE 1=2;CREATE OR REPLACE TRIGGER del_emp BEFORE DELETE ON HAIYA1.emp FOR EACH ROWBEGIN --将修改前数据插入到日志记录表del_emp ,以供监督使用。 INSERT INTO emp_his(deptno, empno, ename, job, sal, comm, hiredate) VALUES( :old.deptno, :old.empno, :old.ename , :old.job, :old.sal, :old.comm, :old.hiredate );END;--删除记录触发触发器DELETE emp WHERE empno=7788;DROP TABLE emp_his;DROP TRIGGER del_emp;--创建替代(Instead_of)触发器--我们可以创建INSTEAD_OF 触发器来为DELETE 操作执行所需的处理,即删除EMP表中所有基准行CREATE OR REPLACE VIEW emp_view AS SELECT deptno, count(*) total_employeer, sum(sal) total_salary FROM emp GROUP BY deptno; select * from emp_view;CREATE OR REPLACE TRIGGER emp_view_delete INSTEAD OF DELETE ON emp_view FOR EACH ROWBEGIN DELETE FROM emp WHERE deptno= :old.deptno;END emp_view_delete;DELETE FROM emp_view WHERE deptno=1;DROP TRIGGER emp_view_delete;DROP VIEW emp_view;--改变一个触发器的状态ALTER TRIGGER del_emp DISABLE;ALTER TRIGGER del_emp ENABLE;--使表EMP上的所有TRIGGER失效/生效ALTER TABLE emp DISABLE ALL TRIGGERS;ALTER TABLE emp ENABLE ALL TRIGGERS;--触发器和数据字典SELECT TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT,TABLE_OWNER, BASE_OBJECT_TYPE, REFERENCING_NAMES,STATUS, ACTION_TYPEFROM user_triggers;--数据库触发器的应用举例BEGIN --创建用于记录事件日志的数据表 DBMS_UTILITY.EXEC_DDL_STATEMENT(' CREATE TABLE eventlog( Eventname VARCHAR2(20) NOT NULL, Eventdate date default sysdate, Inst_num NUMBER NULL, Db_name VARCHAR2(50) NULL, Srv_error NUMBER NULL, Username VARCHAR2(30) NULL, Obj_type VARCHAR2(20) NULL, Obj_name VARCHAR2(30) NULL, Obj_owner VARCHAR2(30) NULL ) '); --创建DDL 触发器trig4_ddl DBMS_UTILITY.EXEC_DDL_STATEMENT(' CREATE OR REPLACE TRIGGER trig_ddl AFTER CREATE OR ALTER OR DROP ON DATABASE DECLARE Event VARCHAR2(20); Typ VARCHAR2(20); Name VARCHAR2(30); Owner VARCHAR2(30); BEGIN --读取DDL 事件属性 Event := SYSEVENT; Typ := DICTIONARY_OBJ_TYPE; Name := DICTIONARY_OBJ_NAME; Owner := DICTIONARY_OBJ_OWNER; --将事件属性插入到事件日志表中 INSERT INTO HAIYA1.eventlog(eventname,obj_type, obj_name, obj_owner) VALUES(event, typ, name, owner); END; '); --创建LOGON、STARTUP 和SERVERERROR 事件触发器 DBMS_UTILITY.EXEC_DDL_STATEMENT(' CREATE OR REPLACE TRIGGER trig_after AFTER LOGON OR STARTUP OR SERVERERROR ON DATABASE DECLARE Event VARCHAR2(20); Instance NUMBER; Err_num NUMBER; Dbname VARCHAR2(50); User VARCHAR2(30); BEGIN Event := SYSEVENT; IF event = ''LOGON'' THEN User := LOGIN_USER; INSERT INTO eventlog(eventname,username) VALUES(event, user); ELSIF event = ''SERVERERROR'' THEN Err_num := SERVER_ERROR(1); INSERT INTO eventlog(eventname,srv_error) VALUES(event, err_num); ELSE Instance := INSTANCE_NUM; Dbname := DATABASE_NAME; INSERT INTO eventlog(eventname,inst_num, db_name) VALUES(event, instance, dbname); END IF; END; '); --创建LOGOFF 和SHUTDOWN 事件触发器 DBMS_UTILITY.EXEC_DDL_STATEMENT(' CREATE OR REPLACE TRIGGER trig_before BEFORE LOGOFF OR SHUTDOWN ON DATABASE DECLARE Event VARCHAR2(20); Instance NUMBER; Dbname VARCHAR2(50); User VARCHAR2(30); BEGIN Event := SYSEVENT; IF event = ''LOGOFF'' THEN User := LOGIN_USER; INSERT INTO eventlog(eventname,username) VALUES(event, user); ELSE Instance := INSTANCE_NUM; Dbname := DATABASE_NAME; INSERT INTO eventlog(eventname,inst_num, db_name) VALUES(event, instance, dbname); END IF; END; ');END;CREATE TABLE mydata(mydate NUMBER);drop table mydata;select * from mydata;SELECT eventname, eventdate, obj_type, obj_name, obj_owner, username, Srv_errorFROM eventlog;select * from eventlog;drop table eventlog;delete eventlog;--删除触发器DROP TRIGGER trig_ddl;DROP TRIGGER trig_before;DROP TRIGGER trig_after;--删除记录事件日志的数据表DROP TABLE eventlog;
请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!
技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成
网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];
文章归档
文章标签
友情链接