1 数据类型
(1)PLSQL支持所有的SQL数据类型
(2)标量:数值、字符、布尔、日期时间
1>. number 包括(decimal、float、integer、real)
2>. oracle11g新加入一种数据类型:SIMPLE_INTEGER 范围(-2147483648 ~ +2147483647)
数据类型不为空.对于此数据类型,ORACLE可以将这个数据类型的操作直接作用于硬件,从而提高性能。
3>. 字符型:SQL: char(长度2000)/varchar2(长度4000) PLSQL: 长度都是32767
4>. boolean (逻辑判断 true、false、null)
v_num1 := 50;
v_num2 := 60;
v_bool := (v_num1 < v_num2);
5>. 日期时间(DATE、TIMESTAMP)
(3)LOB类型(最大可存储4G),用于存储大文本、图像、视频剪辑和声音剪辑等非结构化数据。
BLOB(二进制对象存储)
CLOB(大文本字符)
NCLOB(存储UNICODE字符)
BFILE(讲二进制存储在操作系统中,只读)
(4)复合类型
%TYPE 引用变量和数据库列的数据类型一致
%ROWTYPE 提供表示表中一行的记录类型
(5)对于常量 就是需要用CONSTANT关键字声明并且一定要初始化值 形如: c_salary_rate CONSTANT NUMBER(7,2) := 0.25;
大对象读取示例:(示例准备)
CREATE TABLE MY_BOOK(
CHARTER_ID NUMBER,
CHARTER_TEXT CLOB
);
INSERT INTO MY_BOOK (CHARTER_ID, CHARTER_TEXT) VALUES('5','oracle11g新加入一种数据类型:SIMPLE_INTEGER 范围(-2147483648 ~ +2147483647)
>数据类型不为空.对于此数据类型,ORACLE可以将这个数据类型的操作直接作用于硬件,从而提高性能');
SELECT * FROM MY_BOOK;
drop table my_book;
DECLARE
v_clob CLOB;
v_amount INTEGER;
v_offset INTEGER;
v_outdata VARCHAR2(1000);
BEGIN
SELECT M.CHARTER_TEXT INTO v_clob FROM MY_BOOK M WHERE M.CHARTER_ID = '5';
v_amount := 300;
v_offset := 1;
dbms_lob.read(v_clob, v_amount, v_offset, v_outdata);
dbms_output.put_line(v_outdata);
END;
复合类型
%TYPE(列类型)
DECLARE
v_ename EMP.ENAME%TYPE; --与emp表中的ename类型相同
BEGIN
SELECT E.ENAME INTO v_ename FROM EMP E WHERE E.ENAME = 'SMITH';
DBMS_OUTPUT.put_line(v_ename);
END;
%TYPE绑定某一列
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_hiredate emp.hiredate%TYPE;
BEGIN
SELECT empno, ename, hiredate INTO v_empno, v_ename, v_hiredate FROM emp WHERE empno='7369';
dbms_output.put_line('员工编号:' || v_empno);
dbms_output.put_line('员工姓名:' || v_ename);
dbms_output.put_line('入职日期:' || v_hiredate);
END;
%ROWTYPE定义游标类型的变量
DECLARE
CURSOR cur_emp
IS
SELECT E.EMPNO, E.ENAME, E.JOB FROM EMP E; --使用%rowtype定义游标类型的变量
v_emprow cur_emp%ROWTYPE;
BEGIN
OPEN cur_emp;
LOOP
FETCH cur_emp INTO v_emprow;
--注意退出游标
EXIT WHEN cur_emp%NOTFOUND;
dbms_output.put_line(v_emprow.empno || ' ' || v_emprow.ename || ' ' || v_emprow.job);
END LOOP;
END;
自定义记录类型
--定义一个记录类型
--定义了一个my_record变量
declare
type emp_record_type is record(name emp.ename%type, salary emp.sal%type);
--定义一个my_record变量 这个变量的类型是emp_record_type
my_record emp_record_type;
DECLARE
--自定义类型
TYPE emp_record_type IS RECORD(
NAME emp.ename%TYPE,
salaryemp.sal%TYPE,
title emp.job%TYPE);
--变量接受自定义类型
emp_record emp_record_type;
--执行程序
BEGIN
SELECT E.ENAME, E.SAL, E.JOB INTO emp_record FROM EMP E
WHERE EMPNO = '7788';
DBMS_OUTPUT.put_line('雇员名:' || emp_record.name);
END;
表类型(索引表)
PL/SQL表只有俩列,一个索引列和一列(一列不代表一个字段) 通过索引列中的索引值来操作PL/SQL表中对应的用户自定义列.
declare
--定义了一个pl/sql表类型my_table_type, 该类型是用于存放emp.ename%type
type my_table_type is table of emp.ename%type
--索引列必须是binary_integer类型的
index by binary_integer
--定义了一个my_table变量,这个变量的类型是 my_table_type
my_table my_table_type
DECLARE
TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
BEGIN
SELECT ename INTO ename_table(1) FROM emp WHERE empno = 7788;
dbms_output.put_line(ename_table(1));
END;
PLSQL结构、存储过程、函数
EXCEPTION捕获
[DECLARE declarations]
BEGIN
executable statements
[EXCEPTION handlers]
END;
DECLARE
v_ename emp.ename%TYPE;
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('查无此人!');
END;
条件判断
条件判断
IF boolean THEN executable END IF;
IF boolean THEN executable ELSE executable END IF;
IF boolean THEN executable ELSIF boolean THEN executable ELSE executable END IF;
循环 (LOOP WHILE FOR)
**-- LOOP循环**
DECLARE
j NUMBER := 0;
BEGIN
j := 1;
LOOP
dbms_output.put_line(j);
EXIT WHEN j >= 7;
j := j + 1;
END LOOP;
END;
**-- WHILE循环**
DECLARE
j NUMBER := 0;
BEGIN
j := 1;
WHILE j <= 8
LOOP
dbms_output.put_line(j || '---');
j := j+1;
END LOOP;
END;
**-- FOR循环**
DECLARE
j NUMBER := 0;
BEGIN
FOR j IN 1..8
LOOP
dbms_output.put_line(j || '---');
END LOOP;
END;
存储过程(PROCEDURE)
参数形式三种 (in, outm in out)
CREATE OR REPLACE PROCEDURE PROC1(i IN NUMBER)
AS
a VARCHAR2(50);
BEGIN
a := '';
FOR j IN 1..i
LOOP
a := a || '*';
dbms_output.put_line(a);
END LOOP;
END;
两种方式调用存储过程 1 通过exec执行 2 通过块执行
exec PROC1(4);--第一种
BEGIN
PROC1(7);--第二种
END;
CREATE OR REPLACE PROCEDURE PROC2(i OUT NUMBER)
AS
BEGIN
i := 100;
dbms_output.put_line(i);
END;
DECLARE
k NUMBER;
BEGIN
PROC2(K);
dbms_output.put_line(k);
END;
CREATE OR REPLACE PROCEDURE PROC3(p1 IN OUT NUMBER , p2 IN OUT NUMBER)
AS
v_temp NUMBER;
BEGIN
v_temp := p1;
p1 := p2;
p2 := v_temp;
END;
DECLARE
num1 NUMBER := 10;
num2 NUMBER := 20;
BEGIN
PROC3(num1, num2);
dbms_output.put_line(num1);
dbms_output.put_line(num2);
END;
函数:(函数是可以返回值的命名的PL/SQL 子程序)
CREATE [OR REPLACE] FUNCTION <FUNCTION NAME> [(PARAM...)]
RETURN <DATATYPE> IS|AS
[LOCAL DECLARATIONS]
BEGIN
EXECUTABLE STATEMENTS;
RETURN RESULT;
EXCEPTION
EXCEPTION HANDLERS;
END;
创建一个函数,可以接受用户输入的学号,得到该学生的名次,输出名次。
-- 实验准备
CREATE TABLE STUDENT (STU_NO NUMBER(3), NAME VARCHAR2(10), SCORE NUMBER(3));
INSERT INTO STUDENT VALUES (1 , '小小', 99);
INSERT INTO STUDENT VALUES (2 , '小G', 80);
INSERT INTO STUDENT VALUES (3 , '诺诺', 98);
INSERT INTO STUDENT VALUES (4 , '小北', 79);
COMMIT;
SELECT * FROM STUDENT;
CREATE OR REPLACE FUNCTION FUNC1(SNO INT) RETURN INT
AS
v_score NUMBER;
v_mingci NUMBER;
BEGIN
SELECT SCORE INTO v_score FROM STUDENT WHERE STU_NO = SNO;
SELECT COUNT(*) INTO v_mingci FROM STUDENT WHERE SCORE > v_score;
v_mingci := v_mingci + 1;
RETURN v_mingci;
END;
SELECT FUNC1(3) FROM DUAL;
PL/SQL 游标
游标:三类:
1隐性游标(SQL%FOUND.缺省写法存在、可以捕捉到、很少用)
2显式游标
3参照(REF)游标
操作步骤: 声明游标 -打开游标 -提取行 -变量 -关闭游标.
(1)显式游标写法1:
DECLARE
V_SAL EMP.SAL%TYPE;
CURSOR MYCURSOR IS
SELECT SAL FROM EMP WHERE SAL > 2500;
BEGIN
OPEN MYCURSOR;
LOOP
FETCH MYCURSOR INTO V_SAL;
EXIT WHEN MYCURSOR%NOTFOUND;
DBMS_OUTPUT.put_line('工资为:' || V_SAL);
END LOOP;
CLOSE MYCURSOR;
END;
(2)显式游标写法2:
DECLARE
V_SAL EMP.SAL%TYPE;
--显示游标一定要在DECLARE里面出现
CURSOR MYCURSOR IS
SELECT SAL FROM EMP WHERE SAL > 2500;
BEGIN
--打开游标
OPEN MYCURSOR;
--获取下一个值
FETCH MYCURSOR INTO V_SAL;
--循环
WHILE MYCURSOR%FOUND LOOP
DBMS_OUTPUT.put_line('工资为:' || V_SAL);
FETCH MYCURSOR INTO V_SAL;
END LOOP;
--关闭游标
CLOSE MYCURSOR;
END;
显式游标可以带参数提高灵活性
CURSOR <cursor_name>(<param_name> <param_type>)
IS SELECT STATEMENT
允许使用游标删除或更新活动集中的行
声明游标时必须使用 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>
循环游标用于简化游标处理代码
当用户需要从游标中提取所以记录时使用
循环游标的语法如下:
FOR<record_index> IN <cursor_name>
LOOP
<executable statements>
END LOOP;
(3)带参数的游标
DECLARE
-- 声明学号变量
V_SNO STUDENT.STU_NO%TYPE;
-- 一行多利记录
V_STU STUDENT%ROWTYPE;
CURSOR MYCURSOR(INPUT_NO NUMBER)
IS
SELECT * FROM STUDENT WHERE STU_NO > INPUT_NO;
BEGIN
V_SNO := &学生学号;
OPEN MYCURSOR(V_SNO);
LOOP
FETCH MYCURSOR INTO V_STU;
EXIT WHEN MYCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('学号是:' || V_STU.STU_NO || '姓名是:' || V_STU.NAME);
END LOOP;
CLOSE MYCURSOR;
END;
(4)显式游标 进行更新
DECLARE
V_STU STUDENT%ROWTYPE;
CURSOR MYCURSOR
IS
SELECT * FROM STUDENT WHERE STU_NO = 2 OR STU_NO = 3
FOR UPDATE;
BEGIN
OPEN MYCURSOR;
LOOP
FETCH MYCURSOR INTO V_STU;
EXIT WHEN MYCURSOR%NOTFOUND;
UPDATE STUDENT SET STU_NO = STU_NO + 100
WHERE CURRENT OF MYCURSOR;
END LOOP;
CLOSE MYCURSOR;
END;
(5)显式游标和记录类型结合
DECLARE
--定义一个记录类型
TYPE EMP_RECORD_TYPE IS RECORD(NAME EMP.ENAME%TYPE, SALARY EMP.SAL%TYPE);
--定义变量
V_ET EMP_RECORD_TYPE;
CURSOR MYCURSOR
IS
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 10;
BEGIN
OPEN MYCURSOR;
LOOP
FETCH MYCURSOR INTO V_ET;
EXIT WHEN MYCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('姓名:'|| V_ET.NAME || '薪水:' || V_ET.SALARY);
END LOOP;
CLOSE MYCURSOR;
END;
(6)显式游标和表类型结合
DECLARE
-- 定义一个表类型
TYPE ENAME_TABLE_TYPE
IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
-- 定义变量
V_ET ENAME_TABLE_TYPE;
CURSOR MYCURSOR
IS
SELECT ENAME FROM EMP WHERE DEPTNO = 10;
BEGIN
OPEN MYCURSOR;
FETCH MYCURSOR BULK COLLECT INTO V_ET;
FOR I IN 1..V_ET.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(V_ET(I));
END LOOP;
CLOSE MYCURSOR;
END;
(7)显式游标用于子程序UPDATE
--实验准备
CREATE TABLE PERSON (XH NUMBER, XM VARCHAR2(10));
INSERT INTO PERSON VALUES(1, 'A');
INSERT INTO PERSON VALUES(2, 'B');
INSERT INTO PERSON VALUES(3, 'C');
INSERT INTO PERSON VALUES(4, 'D');
COMMIT;
CREATE TABLE ADDRESS (XH NUMBER, ZZ VARCHAR2(20));
INSERT INTO ADDRESS VALUES(2, '北京');
INSERT INTO ADDRESS VALUES(1, '广州');
INSERT INTO ADDRESS VALUES(3, '上海');
INSERT INTO ADDRESS VALUES(4, '西安');
COMMIT;
SELECT * FROM PERSON;
SELECT * FROM ADDRESS;
ALTER TABLE PERSON ADD ZZ CHAR(10);
DECLARE
V_XH NUMBER;
V_ZZ VARCHAR2(10);
CURSOR MYCURSOR
IS
SELECT XH, ZZ FROM ADDRESS;
BEGIN
OPEN MYCURSOR;
LOOP
FETCH MYCURSOR INTO V_XH, V_ZZ;
EXIT WHEN MYCURSOR%NOTFOUND;
UPDATE PERSON SET ZZ = V_ZZ WHERE XH = V_XH;
END LOOP;
CLOSE MYCURSOR;
END;
UPDATE PERSON P SET P.ZZ = '';
-- 使用SQL也可以实现上面的操作
UPDATE PERSON P SET P.ZZ = (SELECT A.ZZ FROM ADDRESS A WHERE A.XH = P.XH);
参照游标(REF)
游标和游标变量用于处理运行时动态执行的SQL查询
创建游标变量需要俩个步骤:
声明 REF 游标类型
声明 REF 游标类型的变量
用于声明 REF 游标类型的语法为:
TYPE <ref_cursor_name> IS REF CURSOR
[RETURN <return_type>]
DECLARE
TYPE REFCUR IS REF CURSOR;
MYCURSOR REFCUR;
V_TBNAME VARCHAR2(50);
V_NO STUDENT.STU_NO%TYPE;
V_NAME STUDENT.NAME%TYPE;
BEGIN
V_TBNAME := '&表名';
IF V_TBNAME = 'STUDENT' THEN
OPEN MYCURSOR FOR SELECT STU_NO,NAME FROM STUDENT;
LOOP
FETCH MYCURSOR INTO V_NO, V_NAME;
EXIT WHEN MYCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('学号:' || V_NO || '姓名:' || V_NAME);
END LOOP;
CLOSE MYCURSOR;
ELSE
DBMS_OUTPUT.PUT_LINE('表名不正确');
END IF;
END;
PL/SQL 异常处理、触发器
异常处理
异常有俩种类型 预定义异常 - 当PL/SQL 程序违反Oracle规则或超越系统限制时隐式引发 用户定义异常 - 用户可以在PL/SQL块的声明部分定义异常,自定义的异常通过RAISE语句显式引发 命名的系统异常 NO_DATA_FOUND TOO_MANY_ROWS VALUE_ERROR CURSOR_ALREADY_OPEN COLLECTION_IS_NULL ACCESS_INTO_NULL TIMEOUT_ON_RESOURCE ZERO_DIVIDE ... RAISE APPLICATION_ERROR 过程 用于创建用户自定义的错误信息 可以在执行部分和异常处理部分使用 错误编号必须介于 -20000 和 - 20999 之间 错误消息长度最多 2048个字节 引发应用程序错误的语法: RASIE_APPLICATION_ERROR(-20001,'身份证信息与出生日期不符'); 注意RAISE 异常会使程序停止,不会进行后续任何操作
实验准备
CREATE TABLE STUDENT (
SID CHAR(18) PRIMARY KEY,
SNAME CHAR(10),
SBIRTH DATE
);
CREATE OR REPLACE PROCEDURE PROC4(P1 CHAR, P2 CHAR, P3 DATE)
IS
-- 自定义异常
INVALID_DATE EXCEPTION;
V_A CHAR(8);
V_B CHAR(8);
BEGIN
INSERT INTO STUDENT VALUES (P1, P2, P3);
SELECT SUBSTR(P1, 7, 8) INTO V_A FROM STUDENT S WHERE S.SID = P1;
SELECT TO_CHAR(P3,'yyyymmdd') INTO V_B FROM STUDENT S WHERE S.SID = P1;
IF V_A = V_B THEN
COMMIT;
DBMS_OUTPUT.PUT_LINE('插入成功');
ELSE
ROLLBACK;
--升起异常
RAISE INVALID_DATE;
END IF;
EXCEPTION
WHEN INVALID_DATE THEN
--DBMS_OUTPUT.PUT_LINE('身份证信息与出生日期不符!');
RAISE_APPLICATION_ERROR(-20001,'身份证信息与出生日期不符');
END;
DECLARE
V_SID CHAR(18);
V_SNAME CHAR(10);
V_SBIRTH DATE;
BEGIN
V_SID := '220104196708274110';
V_SNAME := 'BHZ';
V_SBIRTH := TO_DATE('19770827','yyyymmdd');
PROC4(V_SID, V_SNAME, V_SBIRTH);
END;
触发器
触发器由三部分组成:
> 1 触发器语句(事件) > 定义集合触发器的DML事件和DDL事件 > 2 触发器限制 > 执行触发器的条件 该条件必须为真才能激活触发器 > 3 触发器操作(主体) > 包含一些SQL语句和代码,他们在发出了触发器语句且触发限制的值为真时运行 > > CREATE [OR REPLACE] TRIGGER trigger_name > AFTER | BEFORE | INSTEAD OF > [INSERT] [ [OR] UPDATE [OF column_list] ] > [[OR] DELETE] > ON table_or_view_name > [REFERENCING { OLD [AS] OLD/NEW [AS] new}] > [FOR EACH ROW] > [WHEN (condition)] > PL/SQL_BLOCK 1 DDL 触发器:在模式中执行 DDL语句时执行 2 数据库触发器:在发生打开、关闭、登陆和退出数据库等系统事件时执行 3 DML 触发器:正在对表或视图执行DML语句时执行 语句级触发器:无论受影响的行数是多少,都只执行一次 行级触发器:对DML语句修改的每个执行一次 INSTEAD OF 触发器:用于用户不能直接使用DML语句修改的视图 4 注意: 触发器里面不能使用(TCL、DDL语句): rollback、commit、savepoint、create、drop、alter等..
当用户插入、更新EMP1表中的记录时,就输入一个提示”TRIG1 BEGIN TO WORK”
实验准备
CREATE TABLE EMP1 AS SELECT * FROM EMP WHERE DEPTNO = 10;
SELECT * FROM EMP1;
CREATE OR REPLACE TRIGGER TRIG1
AFTER INSERT OR UPDATE ON EMP1
BEGIN
DBMS_OUTPUT.PUT_LINE('TRIG1 RESPONDED!');
END;
-- 新增
INSERT INTO EMP1 SELECT * FROM EMP E WHERE E.EMPNO = '7788';
-- 更新
UPDATE EMP1 SET SAL = 3000 WHERE EMPNO = '7782';
行级触发器
CREATE OR REPLACE TRIGGER TRIG2
AFTER UPDATE ON EMP1
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('TRIG2 ROW UPDATE!');
END;
UPDATE EMP1 SET SAL = 4000;
ROLLBACK;
OLD.FIELD :NEW.FIELD 使用,级联触发更新
准备实验
create table PRODUCTS
(
product_id NUMBER(38),
product_name VARCHAR2(60),
category VARCHAR2(60),
CONSTRAINT PK_PRODUCTS PRIMARY KEY (product_id)
);
create table TLOG
(
CHANGE_IDVARCHAR2(32) NOT NULL,
DATA_CODEVARCHAR2(40) NOT NULL,
CHANGE_TYPE VARCHAR2(10) NOT NULL,
CHANGE_BYVARCHAR2(80) NOT NULL,
CHANGE_TIME TIMESTAMPNOT NULL,
CONSTRAINT PK_MST_CHANGE PRIMARY KEY (CHANGE_ID)
);
create table TCOL
(
CHANGE_ID VARCHAR2(32) not null,
COLNAME VARCHAR2(40),
BEFOREVALUE VARCHAR2(256),
AFTERVALUE VARCHAR2(256),
CONSTRAINT PK_TCOL PRIMARY KEY (CHANGE_ID, COLNAME)
);
ALTER TABLE TCOL
ADD CONSTRAINT FK_TCOL FOREIGN KEY (CHANGE_ID)
REFERENCES TLOG (CHANGE_ID);
insert into PRODUCTS (product_id, product_name, category) values (1501, 'VIVITAR 35MM', 'ELECTRNCS');
insert into PRODUCTS (product_id, product_name, category) values (1502, 'OLYMPUS IS50', 'ELECTRNCS');
insert into PRODUCTS (product_id, product_name, category) values (1600, 'PLAY GYM', 'TOYS');
insert into PRODUCTS (product_id, product_name, category) values (1601, 'LAMAZE', 'TOYS');
insert into PRODUCTS (product_id, product_name, category) values (1717, 'HARRY POTTER', 'DVD');
insert into PRODUCTS (product_id, product_name, category) values (1666, 'HARRY POTTER', 'DVD');
insert into PRODUCTS (product_id, product_name, category) values (1718, 'AAA', 'TTT');
commit;
创建触发器
CREATE OR REPLACE TRIGGER t_case_change
AFTER INSERT OR UPDATE
ON PRODUCTS
FOR EACH ROW
DECLARE
v_uid TLOG. CHANGE_ID%TYPE;
v_type TLOG.CHANGE_TYPE%TYPE;
BEGIN
SELECT sys_guid() INTO v_uid FROM DUAL;
IF INSERTING THEN
v_type := 'INSERT';
INSERT INTO TLOG VALUES (v_uid, 'PRODUCTS', v_type, :NEW.PRODUCT_ID, SYSTIMESTAMP);
INSERT INTO TCOL VALUES (v_uid, 'PRODUCT_NAME', :NEW.PRODUCT_NAME, :NEW.PRODUCT_NAME);
INSERT INTO TCOL VALUES (v_uid, 'CATEGORY', :NEW.CATEGORY, :NEW.CATEGORY);
END IF;
IF UPDATING THEN
v_type := 'UPDATE';
INSERT INTO TLOG VALUES (v_uid, 'PRODUCTS', v_type, :OLD.PRODUCT_ID, SYSTIMESTAMP);
IF UPDATING('PRODUCT_NAME') THEN
INSERT INTO TCOL VALUES (v_uid, 'PRODUCT_NAME', :OLD.PRODUCT_NAME, :NEW.PRODUCT_NAME);
END IF;
IF UPDATING('CATEGORY') THEN
INSERT INTO TCOL VALUES (v_uid, 'CATEGORY', :OLD.CATEGORY, :NEW.CATEGORY);
END IF;
END IF;
END;
测试数据
insert into products values(2001, '新增数据2001', '新增版块2001');
insert into products values(2002, '新增数据2002', '新增版块2002');
update products set PRODUCT_NAME = '更新PRODUCT_NAME字段-1' where PRODUCT_ID = '1717' ;
update products set PRODUCT_NAME = '更新PRODUCT_NAME字段-2', CATEGORY = '更新CATEGORY字段-2' where PRODUCT_ID = '1718';
查询语句
select * from products
select * from TLOG
select * from TCOL
truncate table PRODUCTS
truncate table TLOG
truncate table TCOL
PL/SQL 包、定时任务
包
(1)包PACKAGE
DBMS_OUTPUT
DBMS_LOB
DBMS_JOB..
包(包头、包体)
包头: 公共类型的变量、常量、异常、过程、函数等的声明。
包体:私有类型的变量、常量、异常、过程、函数等的声明以及包头内的过程、函数的实现
(2)包规范[包头]
CREATE [OR REPLACE]
PACKAGE <package_name>
IS|AS
[Public item declarations]
[Subprogram specification]
END [package_name];
(3)包规范[包体]
CREATE [OR REPLACE]
PACKAGE BODY <package_nams>
IS|AS
[Private item declarations]
[Subprogram bodies]
[BEGIN Initialization]
END [package_name];
(4)程序包的优点
模块化
更轻松的应用程序设计
信息隐藏
新增功能
性能更佳
包示例
实验准备
CREATE TABLE STUDENT (STU_NO NUMBER(3), NAME VARCHAR2(10), SCORE NUMBER(3));
INSERT INTO STUDENT VALUES (1 , '小小', 99);
INSERT INTO STUDENT VALUES (2 , '小G', 80);
INSERT INTO STUDENT VALUES (3 , '诺诺', 98);
INSERT INTO STUDENT VALUES (4 , '小北', 79);
COMMIT;
SELECT * FROM STUDENT;
包头
CREATE OR REPLACE PACKAGE PACK1
IS
V_A INT := 9;
--定义显示游标1
CURSOR MYCURSOR1 RETURN STUDENT%ROWTYPE;
--定义参照游标1
TYPE REFCUR1 IS REF CURSOR;
--定义参照游标2
TYPE REFCUR2 IS REF CURSOR;
PROCEDURE INSERT_STUDENT(P1 IN STUDENT%ROWTYPE);
PROCEDURE UPDATE_STUDENT(P2 IN STUDENT%ROWTYPE);
--定义过程中使用显示游标
PROCEDURE MYCURSOR1_USE;
--定义过程中使用参照游标1
PROCEDURE REFCUR1_USE;
--定义过程中使用参照游标2
PROCEDURE REGCUR2_USE(P_NO IN NUMBER, P_CURSOR OUT PACK1.REFCUR2);
END PACK1;
包体
CREATE OR REPLACE PACKAGE BODY PACK1
IS
V_B INT := 5;
CURSOR MYCURSOR1 RETURN STUDENT%ROWTYPE
IS
SELECT * FROM STUDENT;
PROCEDURE INSERT_STUDENT(P1 IN STUDENT%ROWTYPE)
IS
BEGIN
INSERT INTO STUDENT(STU_NO, NAME, SCORE)
VALUES(P1.STU_NO, P1.NAME, P1.SCORE);
COMMIT;
END;
PROCEDURE UPDATE_STUDENT(P2 IN STUDENT%ROWTYPE)
IS
BEGIN
UPDATE STUDENT SET NAME = P2.NAME, SCORE = P2.SCORE
WHERE STU_NO = P2.STU_NO;
COMMIT;
END;
PROCEDURE MYCURSOR1_USE
IS
V_STU STUDENT%ROWTYPE;
BEGIN
OPEN MYCURSOR1;
LOOP
FETCH MYCURSOR1 INTO V_STU;
EXIT WHEN MYCURSOR1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('学号为:' || V_STU.STU_NO || '姓名为:' || V_STU.NAME);
END LOOP;
CLOSE MYCURSOR1;
END MYCURSOR1_USE;
PROCEDURE REFCUR1_USE
IS
MYREFCUR1 REFCUR1;
V_STU STUDENT%ROWTYPE;
BEGIN
OPEN MYREFCUR1 FOR SELECT * FROM STUDENT;
LOOP
FETCH MYREFCUR1 INTO V_STU;
EXIT WHEN MYREFCUR1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('学号为:' || V_STU.STU_NO || '姓名为:' || V_STU.NAME);
END LOOP;
CLOSE MYREFCUR1;
END;
PROCEDURE REGCUR2_USE(P_NO IN NUMBER, P_CURSOR OUT PACK1.REFCUR2)
IS
BEGIN
OPEN P_CURSOR FOR SELECT * FROM EMP WHERE DEPTNO = P_NO;
END;
END PACK1;
查看包信息
SELECT OBJECT_NAME, OBJECT_TYPE FROM USER_OBJECTS
WHERE OBJECT_TYPE IN ('PROCEDURE','FUNCTION','PACKAGE','PACKAGE BODY');
--调用PACK1.REGCUR2_USE
DECLARE
MYCURSOR PACK1.REFCUR2;
V_EMP EMP%ROWTYPE;
BEGIN
PACK1.REGCUR2_USE(10,MYCURSOR);
LOOP
FETCH MYCURSOR INTO V_EMP;
EXIT WHEN MYCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('姓名为:' || V_EMP.ENAME);
END LOOP;
END;
定时任务
实验准备
CREATE TABLE TEST(A DATE);
CREATE OR REPLACE PROCEDURE PROC_TEST
IS
BEGIN
INSERT INTO TEST VALUES (SYSDATE);
END;
定义任务
VARIABLE job1 NUMBER;
BEGIN
DBMS_JOB.SUBMIT(:job1, 'PROC_TEST;', SYSDATE, 'SYSDATE+1/1440');
END;
运行任务
BEGIN
DBMS_JOB.RUN(:job1);
END;
删除任务
BEGIN
DBMS_JOB.REMOVE(:job1);
END;
SELECT * FROM TEST;