Oracle是第一个支持关系型数据库理论的产品。至今,Oracle已经成为关系型数据库产品一款最优秀的产品。
Oracle先后经历Oracle 1.0, Oracle 2.0,Oracle 3.0、 Oracle 5.0、 Oracle 6.0、 Oracle7.0、 Oracle8i、 Oracle9i、 Oracle10g、 Oracle11g、 Oracle12c版本的变迁。
云端数据库整合的全新多租户架构
数据自动优化
深度安全防护
简化大数据分析
高效的数据库管理
链接:https://pan.baidu.com/s/1jWQLlFvcMUUmMppDldaxwA?pwd=orcl
提取码:orcl
(1)运行Setup.exe启动安装程序
(2)配置安全更新

(3)安装选项

(4)系统类

(5)Oracle主目录用户

(6)典型配置

(7)检查系统条件

(8)概要

(9)安装


(1)停用Oracle的所有系统服务
(2)通过“开始”菜单运行“Universal Installer”






(3)删除自动存储管理(ASM),在DOS命令行中执行命令:oracle-delete-asnsid+asm。
(4)在“开始”|“运行”框中输入regedit命令,进入注册表菜单窗口删除注册表中与Oracle相关的内容。

(5) 删除相应的环境变量:打开“环境变量”窗口,在“系统变量”列表中找到ORACEL_HOME选项,删除即可。如果系统变量中的CLASSPATH和PATH变量中也存在Oracle设置,那么也一并删除。
(6) 删除“开始”|“程序”中所有Oracle的组和图标。
(7) 删除所有与Oracle相关的目录。
(8) 删除相应目录后重启计算机。
SYS:该用户被默认创建并授予DBA角色,它是Oracle数据库中权限最大的管理员账号。
SYSTEM:被默认创建并授予DBA角色权限仅次于SYS。该用户创建和管理数据库中可显示管理信息的表或视图,以及被Oracle数据库应用和工具使用的各种数据库对象。
SYSMAN:该用户是企业管理的超级管理员账号,该账号能够创建和修改其他管理员账号,同时也能管理数据库实例。
DBSNMP:是Oracle数据库中用于智能代理(Intelligent Agent)的用户,用来监控和管理数据库相关性能。如果停止该用户,则无法提取相关的数据库信息。
SYSDBA是Oracle中具有最高级别的特殊权限,可以执行启动数据库、关闭数据库、建立数据库备份和恢复数据库,以及其他的数据库管理操作。
SYSOPER是Oracle数据库的另一个特权,可以执行启动数据库和关闭数据库,不能建立数据库,也不能执行不完全恢复,可以进行一些基本的操作而不能查看用户数据,不具备DBA角色的任何特权。
Oracle通过方案来组织和维护表、视图、索引等数据库对象。
方案:是一系列逻辑数据结构或对象的集合。一个方案只能够被一个数据库用户所拥有,并且方案的名称与这个用户的名称相同。
Oracle数据库中的每一个用户都拥有一个唯一的方案,他所创建的所有方案对象都保存在自己的方案中
}表 Tables
}视图 Views
}索引 Indexes
}触发器 Triggers
}同义词 Synonyms
}序列 Sequences
}函数、过程和包 Functions, Procedures , Packages
}簇或聚集 Clusters
}数据库链 Database links
}扩展程序库 External procedure libraries
•操作符 Operators
•维 Dimensions
•索引组织表 Index-organized tables
•索引类型 Indextypes
•Java classes, Java resources, Java sources
•实体化视图 Materialized views
•实体化视图日志 Materialized view logs
•对象表 Object tables
•对象类型 Object types
•对象视图 Object views
}表空间 Tablespaces
}用户 Users
}角色 Roles
}回退段 Rollback segments
}目录 Directories

•数据定义语言 Data Definition Language Statements(DDL)
•数据操纵语言 Data Manipulation Language(DML) Statements
•事务控制 Transaction Control Statements
•会话控制 Session Control Statements
•系统控制 System Control Statements
•**嵌入SQL **Embedded SQL Statements

1.必须是以字母开头
2.1–30个字符长度
3.仅能包含A–Z, a–z, 0–9, _,$和 #
4.在同一个用户下表名不能重复。
5.不能是Oracle保留字
| 数据类型 | 说明 |
|---|---|
| **VARCHAR2(**size) | 存放可变长字符数据,最大长度为4000字符 |
| **CHAR(**size) | 存放定长字符数据,最长2000个字符 |
| **NUMBER(**p,s) | **存放数值型数据,**p代表总位数,s代表小数点后位数 |
| LONG | 存放可变长字符数据,最大为2GB(gigabytes) |
| DATE | 存放日期,范围从公元前4712年的1月1日到 公元后9999年的12月31日 |
| CLOB | 存放单字节字符数据,最大为4GB(gigabytes) |
| RAW and LONG RAW | **纯(**Raw)二进制数据 |
| BLOB | 二进制大对象,其最大长度为 4GB(gigabytes) |
| BFILE | 二进制大对象, **存放在外部文件中。**最大长度为4GB(gigabytes) |
CREATE TABLE TABLENAME(
NAME CHAR(20) NOT NULL,
SEX INT
)
创建者必须有创建表的权限
使用子查询创建表–创建表的同时插入行
CREATE TABLE DEPT
AS
SELECT EMPNO,ENAME,SAL*12 ANNSAL,HIREDATE
FROM EMP
WHERE DEPTNO = 30;
ALTER TABLE DEPT
ADD (JOB VARCHAR2(9));
…
RENAME DEPT TO DEPARTMENT;
TRUNCATE YABLE DEPARTMENT;
CREATE TABLE EMP(
EMPNO NUMBER(4),
ENAME VARCHAR2(10),
...
DEPTNO NUMBER(7,2) NOT NULL,
CONSTRAINT EMP_EMPNO_PK PRIMARY KEY(EMPNO)
);
-- 列约束
CREATE TABLE EMP(
EMPNO NUMBER(4),
ENAME VARCHAR2(10) NOT NULL,
JOB VARCHAR2(9),
MMGR NUMBER(4),
......
DEPTNO NUMBER(7,2) NOT NULL
);
--表约束
CREATE TABLE DEPT(
DEPTNO NUMBER(2),
DNAME VARCHAE2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT_DNAME_UK UNIQUE(DNAME)
);
CREATE TABLE dept(
deptno NUMBER(2),
dname VARCHAR2(14),
loc VARCHAR2(13),
CONSTRAINT dept_dname_uk UNIQUE (dname),
--定义主键约束
CONSTRAINT dept_deptno_pk PRIMARY KEY(deptno) );
SQL> CREATE TABLE emp(
2 empno NUMBER(4),
3 ename VARCHAR2(10) NOT NULL,
4 job VARCHAR2(9),
5 mgr NUMBER(4),
6 hiredate DATE,
7 sal NUMBER(7,2),
8 comm NUMBER(7,2),
9 deptno NUMBER(7,2) NOT NULL,
-- 定义外键约束
10 CONSTRAINT emp_deptno_fk FOREIGN KEY (deptno)
11 REFERENCES dept (deptno));
..., deptno NUMBER(2),
CONSTRAINT emp_deptno_ck
CHECK (DEPTNO BETWEEN 10 AND 99),...
视图:视图可看作一个或多个表的子集,是特殊的数据库对象,用于限制对表中指定的表列或数据行的访问。
简单视图与复杂视图
| 特点 | 简单视图 | 复杂视图 |
|---|---|---|
| 表的个数 | 1 | 1个或多个 |
| 是否包含函数 | 否 | 是 |
| 是否包含数据分组 | 否 | 是 |
| 是否允许DML操作 | 是 | 否 |
CREATE SEQUENCE dept_sequence
INCREMENT BY 1
START WITH 91
MAXVALUE 100
NOCACHE
NOCYCLE;
SELECT sequence_name, min_value, max_value,
increment_by, last_number
FROM user_sequences
where sequence_name='DEPT_SEQUENCE';
1.NEXTVAL返回下一个有效的序列值。
2.CURRVAL得到当前的序列值。
3.第一次使用序列时必须首先调用NEXTVAL,否则CURRVAL不会包含任何值。
INSERT INTO dept(deptno, dname, loc)
VALUES (dept_sequence.NEXTVAL,
'MARKETING', 'SAN DIEGO');
SELECT dept_sequence.CURRVAL
FROM dual;
-- dual是一个虚拟表
ALTER SEQUENCE dept_sequence
INCREMENT BY 1
MAXVALUE 999999
NOCACHE
NOCYCLE;
-- 第一种插入方式
INSERT INTO DEPT(DEPTNO,DNAME,LOC)
VALUES (50,'DEVELOPMENT','DETROIT');
-- 第二种插入方式
INSERT INTO EMP
VALUES (70,'FINANCE',NULL);
-- 插入多行数据,注意不能使用VALUE子句ORACLEVALUE子句不支持插入多行
INSERT INTO MANAGERS(ID,NAME,SALARY,HIREDATE)
SELECT EMPNO,ENAME,SAL,HIREDATE
FROM EMP
WHERE JOB = 'MANAGER';
UPDATE EMP
SET DEPTNO = 20
-- 如果不添加限制条件就是更新整张表的DEPTNO
WHERE DEPNO = 7782;
DELETE FROM DEPT WHERE DEPTNO = 50;
SELECT * FROM DEPT;
SELECT DEPTNO,LOC
FROM DEPT;
SELECT ENAME,SAL,SAL+300
FROM EMP;
SELECT ENAME AS NAME,SAL SALARY
FROM EMP;
SELECT ENAME ||' '||'is a'||' '||JOB
AS "Employee Details"
FROM EMP;
使用DISTINCT关键字消除所选择的重复行,只返回一行
SELECT DISTNCT DEPTNO
FROM EMP;


SELECT ENAME,SAL
FROM EMP
WHERE SAL BETWEEN 1000 AND 1500;
SELECT EMPNO,ENAME,SAL,MGR
FROM EMP
WHERE MGR IN(7902,7566,7788);
SELECT ENAME
FROM EMP
WHERE ENAME LIKE '_A%';
-- 使用ESCAPE定义查找[ % ]与[ _ ]字符
SELECT ENAME FROM EMP WHERE ENAME LIKE '%A\_B%' ESCAPE '\'
SELECT ENAME,MGR
FROM EMP
WHERE MGR IS NULL;

-- AND
SELECT EMPNO,ENAME,JOB,SAL
FROM EMP
WHERE SAL >= 1000
AND JON = 'CLERK';
-- OR
SELECT EMPNO,ENAME,JOB,SAL
FROM EMP
WHERE SAL >= 1100
OR JOB = 'CLERK';
-- NOT
SELECT ENAME,JOB
FROM EMP
WHERE JOB NOT IN ('CLERK','MANAGER','ANALYST');
| 优先级 | 操作符 |
|---|---|
| 1 | 所有比较操作符 |
| 2 | NOT |
| 3 | AND |
| 4 | OR |
SELECT *
FROM EMP
WHERE JOB='SALESMAN'
--优先描述OR
OR JOB='PRESIDENT'
AND SAL>1500;
SELECT *
FROM EMP
WHERE (JOB='SALESMAN'
OR JOB='PRESIDENT')
--文字描述为:查询工作岗位为销售员并且工资大于1500的员工信息,或者工作岗位是负责人并且工资大于1500的员工信息
AND SAL>1500;
SELECT ENAME,JOB,DEPTNO,HIREDATE
FROM EMP
ORDER BY HIREDATE DESC;
-- ASC从小到大排序(default)
-- DESC 从大到小排序
-- ORDER BY 子句在SELECT语句的最后面


| 函数 | 说 明 |
|---|---|
| LPAD(X, Y [,Z]) | 在字符串X的左边加入字符Z(默认的字符是空格),加入字符的个数为Y。 |
| RPAD(X, Y [,Z]) | 在字符串X的右边加入字符Z(默认的字符是空格),加入字符的个数为Y。 |
| LOWER(X) | 把字符串X所有的字符转换成小写。 |
| UPPER(X) | 把字符串X所有的字符转换成大写 |
| INITCAP(X) | 把字符串X的每个英文单词的第一个字符转换成大写,其它字符转换的成小写。 |
| LENGTH(X) | 返回字符串X的长度。 |
| SUBSTR(X, Y [,Z]) | 从字符串X的第Y个字符开始,取出Z个字符(默认取出所有字符)。 序号是从1开始的。 |
| INSTR(X, Y) | 字符串Y在字符串X中的位置。 返回0表示没有找到。 |
| CONCAT(X, Y) | 把字符串X和字符串Y连接在一起。 |
SELECT ENAME,CONCAT(ENAME,JOB),LENGTH(ENAME),INSTR(ENAME,'a')
FROM EMP
WHERE SUBSTR(JOB,1,5) = 'SALES';
| 数值函数 | 返回值 |
|---|---|
| ABS(n) | 绝对值 |
| ROUND(n [,m]) | 返回将 n 四舍五入到小数点右边 m 位的值。当 m 忽略时,四舍五入到个位。当 m 为负时,四舍五入到小数点左边数字。 |
| CEIL(n) | 返回大于或等于 n 的最小整数。 |
| FLOOR(n) | 返回等于或小于 n 的最大整数。 |
| MOD(m,n) | 返回 m 除以 n 的余数,如果 n=0,则返回m。 |
| SIGN(n) | 当 n<0,返回 -1,当 n=0,返回 0,当 n>0,返回 1。 |
| SQRT(n) | 返回 n 的平方根。 |
| TRUNC(n [,m]) | 返回在 m 位截断的 n 值,当 m 忽略,在 0 **位截断;**m 为负,将小数点左边 m 个数字截断。 |
--ROUND
SELECT ROUND(45.923,2),ROUND(45.923,0),ROUND(45,923,-1)
FROM DUAL;
--TRUNC
SELECT TRUNC(45.923,2),TRUNC(45.923),TRUNC(45.923,-1)
FROM DUAL;
--MOD
SELECT ENAME,SAL,COMM,MOD(SAL,COMM)
FROM EMP
WHERE JOB='SALESMAN';

SELECT SYSDATE FROM DUAL;
SELECT TO_CHAR(SYSDATE,YYYY-MM-DD HH24:MI:SS) FROM DUAL;

SELECT ENAME,(SYSDATE-HIREDATE)/7 WEEKS
FROM EMP
WHERE DEPTNO = 10;











1.NVL(expr1,expr2)

2.NVL2(expr1,expr2,expr3)



tips:单行函数能够在任何一个层次嵌套

在进行连接表时,应该避免笛卡尔积
种类:相等连接、不相等连接、外连接、自连接



select emp.empno,emp.ename,emp.deptno
from emp,dept
where emp.deptno=dept.deptno;

select e.ename,e.sal,s.grade
from emp e,salgrade s
where e.sal
between s.losal and s.hisal;


-- (+)符号表示添加右边自己所没有的数据,左边没有就会使用null代替
select table.column,table.column
from table1,table2
where table.column(+)=table2.column;
-- (+)在右边与上面的含义相反
select table.column,table.column
from table1,table2
where table.column=table2.column(+);
例子:

select e.ename,d.depyno,d.dname
from emp e,dept d
where e.deptno(+)=d.deptno
order by e.deptno;

select ename,dname
from emp full outer join dept
on dept.deptno = emp.deptno;


SELECT worker.ename||' works for '||manager.ename
FROM emp worker, emp manager
WHERE worker.mgr = manager.empno;
-- 两根竖线表示连接符号


SELECT lpad(ename,length(ename)+(level-1)*3,'-') employee,level
FROM emp
START WITH ename = 'KING'
CONNECT BY PRIOR empno = mgr;
--lpad函数表示往左填充


SELECT empno, ename,level
FROM emp
START WITH ename = 'JONES'
CONNECT BY PRIOR empno = mgr;

SELECT empno, ename,level
FROM emp
START WITH ename = 'JONES'
CONNECT BY empno = PRIOR mgr;












select deptno ,avg(sal)
from emp
group by deptno;

select deptno,job,sum(sal)
from emp
froup by deptno,job;


select deptno ,max(sal)
from emp
group by deptno
having max(sal)>2900;
select max(avg(sal))
from emp
group by deptno;
-- 这是错误代码示范
select deptno ,count(ename)
from emp;
在where子句中不能直接使用组函数
在having子句可以直接使用组函数
select deptno,avg(sal)
from emp
where avg(sal)>2000
group by deptno;
select ename
from emp
where sal>(select sal from emo where empno=7566);



select ename,job
from emp
where job = (select job from emp where empno=7369)
and sal >(select sal from emp where empno = 7876);



-- any
select empno,ename,job
from emp
where sal<any (select sal from emp where job = 'clerk') and job<>'clerk';
-- all
select empno,ename,job
from emp
where sal>all(select avg(sal) from emp group by deptno);
SELECT e.empno, e.ename
FROM emp e
WHERE EXISTS (SELECT ‘X’
FROM dept d
WHERE e.deptno=d.deptno
and d.loc= 'NEW YORK');
----------------------
SELECT e.empno, e.ename
FROM emp e
WHERE e.deptno in (SELECT d.deptno
FROM dept d
WHERE d.loc= 'NEW YORK');
SELECT e.empno, e.ename
FROM emp e
WHERE e.deptno in (SELECT d.deptno
FROM dept d
WHERE d.loc= 'NEW YORK'
or d.loc= 'CHICAGO');
---------------
SELECT e.empno, e.ename,d.loc
FROM emp e,
(SELECT deptno,loc FROM dept
WHERE loc= ‘NEW YORK’ or loc= 'CHICAGO') d
WHERE e.deptno =d.deptno;
SELECT select_list
FROM (SELECT select_list
FROM table);
WHERE expr
------------------
SELECT e.empno, e.ename,d.loc
FROM emp e,
(SELECT deptno,loc FROM dept
WHERE loc= ‘NEW YORK’ or loc= 'CHICAGO') d
WHERE e.deptno =d.deptno;
--------------
SELECT e.empno, e.ename,d.loc
FROM emp e, dept d
WHERE e.deptno =d.deptno
and (d.loc= ‘NEW YORK’ or d.loc= 'CHICAGO') ;





update emp
set deptno = 10
where empno = 7782;
------1 row updated.
commit;
------Commit complete.
delete from employee;
------14 rows deleted.
rollback;
------Rollback complete.
update emp
set deptno = 10
where deptno = 7782;
savepoint update_done;
------Savepoint created.
insert into emp
select * from emp_temp;
rollback to update_done;
------Rollback complete.






declare
v_n number(20);
begin
v_n := 65/0;
exception
when zero_divide then
dbms_output.put_line('divided by zero');
end;



declare
v_ename varchar2(10);
v_sal number(6,2);
c_tax_rate constant number(3,2) :=5.5;
v_hirdate date;
v_valid boolean not null default false;

v_hiredate := '31-DEC-98';
v_ename := '张三';








v_job VARCHAR2(9) DEFAULT ‘CLERK';
v_count BINARY_INTEGER := 0;
v_total_sal NUMBER(9,2) := 0;
v_orderdate DATE := SYSDATE + 7;
c_tax_rate CONSTANT NUMBER(3,2) := 8.25;
v_valid BOOLEAN NOT NULL := TRUE;


...
v_ename emp.ename%TYPE;
v_balance NUMBER(7,2);
v_min_balance v_balance%TYPE := 10;
v_emp emp%rowtype;
...








if v_ename='zhangsan' then
v_mgr:=22;
end if;



CASE grade
WHEN 'A' THEN dbms_output.put_line('Excellent');
WHEN 'B' THEN dbms_output.put_line('Very Good');
WHEN 'C' THEN dbms_output.put_line('Good');
WHEN 'D' THEN dbms_output.put_line('Fair');
WHEN 'E' THEN dbms_output.put_line('Poor');
ELSE dbms_output.put_line('No such grade');
END CASE;
-- if 块:--------------------------------
IF grade = 'A' THEN dbms_output.put_line('Excellent');
ELSIF grade = 'B' THEN dbms_output.put_line('Very Good');
ELSIF grade = 'C' THEN dbms_output.put_line('Good');
ELSIF grade = 'D' THEN dbms_output. put_line('Fair');
ELSIF grade = 'E' THEN dbms_output.put_line('Poor');
ELSE
dbms_output.put_line('No such grade');
END IF;




DECLARE
v_num NUMBER(2):=# --用户任意给定的一个整数
v_pro NUMBER(20):=1;
i NUMBER(2):=1; --控制循环结束的循环变量
BEGIN
IF v_num=0 THEN
v_pro:=1;
ELSE
LOOP
v_pro:=v_pro*i; --计算给定整数的阶乘
i:=i+1;
EXIT WHEN i>v_num;
END LOOP;
END IF;
dbms_output.put_line('num:'||v_num||' factorial:'||v_pro);
END;



DECLARE
v_num NUMBER(2):=#
v_pro NUMBER(20):=1;
BEGIN
IF v_num=0 THEN
v_pro:=1;
ELSE
FOR i IN 1..v_num LOOP
v_pro:=v_pro*i;
END LOOP;
END IF;
dbms_output.put_line('num:'||v_num||' factorial:'||v_pro);
--dbms_output.put('num:'||v_num);
--dbms_output.put_line(' factorial:'||v_pro);
END;



DECLARE
v_num NUMBER(2):=#
v_pro NUMBER(20):=1;
i NUMBER(2):=1;
BEGIN
IF v_num=0 THEN
v_pro:=1;
ELSE
WHILE i<=v_num LOOP
v_pro:=v_pro*i;
i:=i+1;
END LOOP;
END IF;
dbms_output.put_line('num:'||v_num||' factorial:'||v_pro);
END;

...
BEGIN
<<Outer_loop>>
LOOP
v_counter := v_counter+1;
EXIT WHEN v_counter>10;
<<Inner_loop>>
LOOP
...
EXIT Outer_loop WHEN total_done = 'YES';
-- Leave both loops
EXIT WHEN inner_done = 'YES';
-- Leave inner loop only
...
END LOOP Inner_loop;
...
END LOOP Outer_loop;
END;


| 属性 | 含义 |
|---|---|
| SQL%ROWCOUNT | 返回最近执行的SQL语句,所影响的行数(一个整数值)。 |
| SQL%FOUND | Boolean属性,如果最近执行的SQL语句影响了一行或多行则返回TRUE。 |
| SQL%NOTFOUND | Boolean属性,如果最近执行的SQL语句没有影响了任何行则返回TRUE。 |
| SQL%ISOPEN | ORACLE在执行每一个相关的SQL语句后,自动地关闭SQL游标,所以返回值总是FALSE |

set serveroutput on;
DECLARE
v_empno NUMBER := 7788;
rows_deleted VARCHAR2(100);
BEGIN
DELETE FROM emp
WHERE empno = v_empno;
rows_deleted := SQL%ROWCOUNT||' rows deleted.';
dbms_output.put_line(rows_deleted);
END;





DECLARE
CURSOR c1 IS
SELECT empno, ename
FROM emp;
CURSOR c2 IS
SELECT *
FROM dept
WHERE deptno = 10;
BEGIN
...





DECLARE
CURSOR c1 IS SELECT * FROM emp;
emp_rec emp%ROWTYPE; --定义一个和表结构完全一致的记录变量
BEGIN
OPEN c1;
FETCH c1 INTO emp_rec;
dbms_output.put_line('姓名是:'||emp_rec.ename|| '工作是:'||emp_rec.job|| '工资是:'||emp_rec.sal);
FETCH c1 INTO emp_rec;
dbms_output.put_line('姓名是:'||emp_rec.ename||'工作是:'||emp_rec.job|| '工资是:'||emp_rec.sal);
CLOSE c1;
END;





IF NOT c1%ISOPEN THEN
OPEN c1;
END IF;
LOOP
FETCH c1...



DECLARE
CURSOR emp_cursor IS
SELECT ename,sal FROM emp WHERE deptno=10;
emp_record emp%ROWTYPE;
BEGIN
OPEN emp_cursor ;
LOOP
FETCH emp_cursor INTO emp_record.ename,emp_record.sal;
EXIT WHEN emp_cursor%NOTFOUND;
dbms_output.put_line('ename: '||emp_record.ename||' sal:'||emp_record.sal);
END LOOP;
dbms_output.put_line('row count:'||emp_cursor%rowcount);
CLOSE emp_cursor;
END;

DECLARE
CURSOR emp_cursor IS
SELECT ename,sal FROM emp WHERE deptno=10;
emp_record emp%ROWTYPE;
BEGIN
OPEN emp_cursor ;
FETCH emp_cursor INTO emp_record.ename,emp_record.sal;
while emp_cursor%FOUND LOOP
dbms_output.put_line('ename: '||emp_record.ename||' sal:'||emp_record.sal);
FETCH emp_cursor INTO emp_record.ename,emp_record.sal;
END LOOP;
dbms_output.put_line('row count:'||emp_cursor%rowcount);
CLOSE emp_cursor;
END;



DECLARE
CURSOR emp_cursor IS
SELECT ename,sal FROM scott.emp WHERE deptno=10;
BEGIN
FOR emp_record IN emp_cursor LOOP
dbms_output.put_line('ename: '||emp_record.ename||' sal:'||emp_record.sal);
END LOOP;
/* 该命令无效,因为FOR循环结束后游标自动关闭
dbms_output.put_line('row count:'||emp_cursor%rowcount); */
END;

DECLARE
CURSOR cur IS SELECT * FROM scott.emp ORDER BY sal DESC;
BEGIN
FOR rec IN cur LOOP
IF cur%ROWCOUNT<=5 THEN
dbms_output.put_line('ename:'||rec.ename||’sal:'||rec.sal);
ELSE
EXIT;
END IF;
END LOOP;
END;



EXCEPTION
WHEN exception1 [OR exception2 . . .] THEN
statement1;
statement2;
. . .
[WHEN exception3 [OR exception4 . . .] THEN
statement1;
statement2;
. . .]
[WHEN OTHERS THEN
statement1;
statement2;
. . .]


BEGIN SELECT ... COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
statement1;
statement2;
WHEN TOO_MANY_ROWS THEN
statement1;
WHEN OTHERS THEN
statement1;
statement2;
statement3;
END;
---------------------
DECLARE
v_empRecord emp%ROWTYPE;
v_empNo emp.empno%TYPE;
BEGIN
SELECT * INTO v_empRecord FROM emp;
--SELECT * INTO v_empRecord FROM emp WHERE empno = 12345789 ;
--SELECT ename INTO v_empNo FROM emp WHERE empno = 7369;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('TOO_MANY_ROWS EXCEPTION');
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('NO_DATA_FOUND EXCEPTION');
WHEN OTHERS THEN
dbms_output.put_line('OTHERS EXCEPTION');
END;


CREATE OR REPLACE PROCEDURE insert_emp
(no IN emp.empno%TYPE, name IN emp.ename%TYPE DEFAULT NULL,
job IN emp.job%TYPE DEFAULT 'SALESMAN',
mgr IN emp.mgr%TYPE DEFAULT 7369,
hiredate emp.hiredate%TYPE DEFAULT SYSDATE,
salary emp.sal%TYPE DEFAULT 800,
comm emp.comm%TYPE DEFAULT NULL,
deptno emp.deptno%TYPE DEFAULT 10
)IS
e_integrity EXCEPTION;
PRAGMA EXCEPTION_INIT (e_integrity,-2291);
BEGIN
INSERT INTO emp VALUES(no,name,job,mgr,hiredate,salary,comm,deptno);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
dbms_output.put_line('该员工已经存在!');
WHEN e_integrity THEN
dbms_output.put_line('部门编号填写错误!');
END;

[DECLARE]
e_amount_remaining EXCEPTION;
. . .
BEGIN
. . .
RAISE e_amount_remaining;
. . .
EXCEPTION
WHEN e_amount_remaining THEN
:g_message := 'There is still an amount
in stock.';
. . .
END;

DECLARE
ex_null EXCEPTION; --系统非预定义异常的定义和关联
PRAGMA EXCEPTION_INIT(ex_null,-01400);
ex_insert EXCEPTION; --用户自定义异常的定义
eno scott.emp.empno%TYPE:=&no; --定义程序块变量
e_sal scott.emp.sal%TYPE:=&salary;
BEGIN
IF e_sal>10000 THEN
RAISE ex_insert; --用户自定义异常的触发
END IF;
INSERT INTO scott.emp(empno,sal) VALUES(eno,e_sal);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN --系统预定义异常的捕获和处理
dbms_output.put_line('该员工已经存在!');
WHEN ex_null THEN --系统非预定义异常的捕获和处理
dbms_output.put_line('职工编号不能为空!');
WHEN ex_insert THEN --用户自定义异常的捕获和处理
dbms_output.put_line('员工的工资不能超过10000!');
END;

DECLARE
v_error_code NUMBER;
v_error_message VARCHAR2(255);
BEGIN
...
EXCEPTION
...
WHEN OTHERS THEN
ROLLBACK;
v_error_code := SQLCODE ;
v_error_message := SQLERRM ;
INSERT INTO errors VALUES(v_error_code,
v_error_message);
END;









| 类别 | 取值 | 说 明 |
|---|---|---|
| 语句 | INSERT、UPDATE、 DELETE | 定义那种DML语句会激发触发器 |
| 定时 | BEFORE或AFTER | 定义在语句执行以前还是在语句执行以后激发触发器 |
| 级别 | 行或语句 | 如果触发器是行级(row-level)触发器,该触发器就对由触发语句影响的每一行激发一次。如果触发器是语句级的触发器,则该触发器就在语句之前或者之后激发一次。行级触发器由触发器定义中的FOR EACH ROW子句标识。 |

CREATE OR REPLACE TRIGGER TR_STMBEFORE
BEFORE DELETE ON EMP
BEGIN
DBMS_OUTPUT.PUT_LINE('STM BEFORE');
END TR_STMBEFORE;
/
CREATE OR REPLACE TRIGGER TR_STMAFTER
AFTER DELETE ON EMP
BEGIN
DBMS_OUTPUT.PUT_LINE('STM AFTER');
END;
/
-------------------------
CREATE OR REPLACE TRIGGER TR_ROWBEFORE
BEFORE DELETE ON EMP
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('ROW BEFORE DELETE EMPNO:'||:OLD.EMPNO);
END TR_STMBEFORE;
/
CREATE OR REPLACE TRIGGER TR_ROWAFTER
AFTER DELETE ON EMP
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('ROW AFTER DELETE EMPNO:'||:OLD.EMPNO);
END TR_STMBEFORE;
/
CREATE OR REPLACE TRIGGER secure_emp
BEFORE INSERT ON emp
BEGIN
IF (TO_CHAR(SYSDATE, 'DY') IN ('星期六', '星期天'))
OR (TO_CHAR(SYSDATE, 'HH24:MI') NOT BETWEEN '08:00' AND '18:00')
THEN
RAISE_APPLICATION_ERROR
(-20500, 'You may insert into EMP table only during business hours.');
END IF;
END;
CREATE OR REPLACE TRIGGER secure_emp
BEFORE INSERT OR UPDATE OR DELETE ON EMP
BEGIN
IF (TO_CHAR(SYSDATE, 'DY') IN ('星期六', '星期天'))
OR (TO_CHAR(SYSDATE, 'HH24') NOT BETWEEN '08' AND '18')
THEN
IF DELETING THEN
RAISE_APPLICATION_ERROR (-20502, 'You may delete from EMP table only during business hours.');
ELSIF INSERTING THEN
RAISE_APPLICATION_ERROR (-20500,'You may insert into EMP table only during business hours.');
ELSIF UPDATING ('SAL') THEN
RAISE_APPLICATION_ERROR (-20503,'You may update SAL only during business hours.');
ELSE
RAISE_APPLICATION_ERROR (-20504,'You may update EMP table only during normal hours.');
END IF;
END IF;
END;
CREATE OR REPLACE TRIGGER restrict_salary
BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW
BEGIN
IF NOT (:NEW.job IN ('PRESIDENT', 'MANAGER', 'ANALYST')) AND :NEW.sal > 2500
THEN
RAISE_APPLICATION_ERROR (-20202, 'Employee cannot earn this amount');
END IF;
END;


CREATE OR REPLACE TRIGGER audit_emp_values
AFTER DELETE OR INSERT OR UPDATE ON emp
FOR EACH ROW
BEGIN
INSERT INTO audit_emp_table (user_name, timestamp,empno,
old_ename, new_ename, old_job,new_job, old_sal, new_sal)
VALUES (USER, SYSDATE, :OLD.empno,:OLD.ename, :NEW.ename,
:OLD.job,:NEW.job, :OLD.sal, :NEW.sal );
END;
-- t_oplog(user,optime,opcontent)
CREATE OR REPLACE TRIGGER derive_commission_pct
BEFORE INSERT OR UPDATE OF sal ON emp
FOR EACH ROW
WHEN (NEW.job = 'SALESMAN')
BEGIN
IF INSERTING THEN :NEW.comm := 0;
ELSIF :OLD.comm IS NULL THEN :NEW.comm := 0;
ELSE :NEW.comm := :NEW.sal*0.10;
END IF;
END;

create or replace TRIGGER tri_insert_emp
BEFORE INSERT ON emp
FOR EACH ROW
BEGIN
if :new.deptno is null then
:new.deptno:=10;
ELSIF :new.deptno=30 then
:new.job:='SALSEMAN';
end if;
SELECT seq_empno.NEXTVAL
INTO :new.empno
FROM dual;
END tri_insert_emp;
CREATE SEQUENCE SEQ_EMPNO
START WITH 9000
MAXVALUE 9999;
insert into emp (ename,sal) values (‘LL',2300);
insert into emp (empno,ename,sal) values (9100,‘HH',2500);



















| IN | OUT | IN OUT |
|---|---|---|
| 默认模式 | 必须说明 | 必须说明 |
| 调用过程时,实际参数取值被传递给过程。 | 过程结束时,形参的内容将赋给实参。把值返回给调用环境。 | 调用过程时,实际参数取值被传递给过程。过程结束时,形参的内容将赋给实参。把值返回给调用环境。 |
| 在过程内部,形式参数是常数,不能改变。 | 形式参数不能被初始化,只能被赋值。当过程调用时,实参中具有的任何值将被忽略。 | 实际参数变量必须初始化。 |
| 实际参数可以是直接量、常数、表达式和初始化了的变量。 | 实际参数必需是变量 | 实际参数必需是变量。 |
| 能够拥有缺省值 | 不能分配缺省值 | 不能分配缺省值 |

CREATE OR REPLACE PROCEDURE raise_salary
(p_id IN emp.empno%TYPE) IS
BEGIN
UPDATE emp SET sal = sal * 1.10 WHERE empno = p_id;
END raise_salary;
---------------------------
--执行
DECLARE
v_empno emp.empno%TYPE:=&no;
BEGIN
raise_salary(v_empno);
END;
CREATE OR REPLACE PROCEDURE query_emp
(p_id IN emp.empno%TYPE, p_name OUT emp.ename%TYPE,
p_salary OUT emp.sal%TYPE,p_comm OUT emp.comm%TYPE)
IS
BEGIN
SELECT ename, sal, comm
INTO p_name, p_salary, p_comm
FROM emp WHERE empno = p_id;
END query_emp;
-------------------
--执行
DECLARE
v_empno emp.empno%TYPE:=&no;
v_name emp.ename%TYPE;
v_salary emp.sal%TYPE;
v_comm emp.comm%TYPE;
BEGIN
query_emp(v_empno,v_name,v_salary,v_comm);
dbms_output.put_line(v_empno||' '||v_name||' '||v_salary||' '||v_comm);
END;

CREATE OR REPLACE PROCEDURE swap
(x IN OUT NUMBER ,y IN OUT NUMBER)
IS
z NUMBER;
BEGIN
z:=x;
x:=y;
y:=z;
END swap;

DECLARE
a NUMBER:=10;
b NUMBER:=20;
BEGIN
dbms_output.put_line('交换前a和b的值是:'||a||' '||b);
swap(a,b);
dbms_output.put_line('交换后a和b的值是:'||a||' '||b);
END;
CREATE OR REPLACE PROCEDURE add_dept
(p_name IN dept.dname%TYPE DEFAULT 'unknown',
p_loc IN dept.loc%TYPE DEFAULT 'NEW YORK')
IS
BEGIN
INSERT INTO dept (deptno,dname, loc)
VALUES (dept_seq.NEXTVAL, p_name, p_loc);
END add_dept;
BEGIN
add_dept;
add_dept ('TRAINING');
add_dept ( p_loc =>'BOSTON ', p_name => 'EDUCATION');
add_dept ( p_loc => 'CHICAGO') ;
END; /
--------------------
select * from dept;
--例8.4 为scott.emp表创建一个能完成插入功能的存储过程insert_emp。
CREATE OR REPLACE PROCEDURE insert_emp
(no IN scott.emp.empno%TYPE,
name IN scott.emp.ename%TYPE DEFAULT NULL,
job IN scott.emp.job%TYPE DEFAULT 'SALESMAN',
mgr IN scott.emp.mgr%TYPE DEFAULT 7369,
hiredate scott.emp.hiredate%TYPE DEFAULT SYSDATE,
salary scott.emp.sal%TYPE DEFAULT 800,
comm scott.emp.comm%TYPE DEFAULT NULL,
deptno scott.emp.deptno%TYPE DEFAULT 10) IS
e_integrity EXCEPTION;
PRAGMA EXCEPTION_INIT (e_integrity,-2291);
BEGIN
INSERT INTO scott.emp VALUES(no,name,job,mgr,hiredate,salary,comm,deptno);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN dbms_output.put_line('该员工已经存在!');
WHEN e_integrity THEN dbms_output.put_line('部门编号填写错误!');
END;



CREATE [OR REPLACE] FUNCTION function_name
[(argument1 [IN | OUT | IN OUT] data_type , argument2 [IN | OUT | IN OUT] data_type,…)]
RETURN data_type
IS |AS
[declaration_section;]
BEGIN
executable_section;
RETURN expression;
[EXCEPTION
exception_handlers;
RETURN expression;
END [function_name];

CREATE OR REPLACE FUNCTION get_sal
(p_id IN emp.empno%TYPE)
RETURN NUMBER
IS
v_salary emp.sal%TYPE :=0;
BEGIN
SELECT sal INTO v_salary FROM emp WHERE empno = p_id;
RETURN v_salary;
END get_sal;




--例 创建函数,从scott.emp表中查询指定编号职工的工资。
CREATE OR REPLACE FUNCTION select_sal
(no scott.emp.empno%TYPE)
RETURN scott.emp.sal%TYPE
IS
salary scott.emp.sal%TYPE;
BEGIN
SELECT sal INTO salary FROM scott.emp WHERE empno=no;
RETURN salary;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 0;
END;
--例 创建函数,从scott.emp表中查询指定员编号工的工资和姓名。
CREATE OR REPLACE FUNCTION select_name_sal
(p_empno in number, p_name out varchar2)
RETURN number
IS
v_result number;
BEGIN
SELECT sal ,ename INTO v_result ,p_name FROM emp WHERE empno= p_empno;
RETURN v_result;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('无符合要求的记录');
v_result:=0;
p_name:='';
RETURN v_result;
END;
----------------------
--例 创建函数,从scott.emp表中查询指定员编号工的工资和姓名。
CREATE OR REPLACE FUNCTION SELECT_NAME_SAL
(P_EMPNO IN NUMBER,P_SAL OUT NUMBER, P_NAME OUT VARCHAR2)
RETURN NUMBER --0 表示成功 1表示异常 员工编号不存在
IS
V_RESULT NUMBER:=0;
BEGIN
SELECT SAL ,ENAME INTO P_SAL ,P_NAME FROM EMP WHERE EMPNO= P_EMPNO;
RETURN V_RESULT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('无符合要求的记录');
V_RESULT:=1;
RETURN V_RESULT;
END;