目录

  • Oracle
    • 1. Oracle 概述
      • a. 常见数据库
      • b. Oracle 简介
    • 2. Oracle 的组成
      • a. Oracle 11g 数据库的组成
      • b. Oracle 11g 数据库服务
    • 3. 连接 Oracle
      • a. SQL Plus 连接
      • b. SQL Developer 连接
      • c. PLSQL Developer 连接
      • d. Jdbc 连接
    • 4. SQL Plus 设置与常用命令
      • a. 显示设置
      • b. 常用命令
    • 5. 表空间
      • a. 表空间类型
      • b. 操作与运用
    • 6. 数据库用户
      • a. 系统常见用户
      • b. 用户管理
    • 7. DCL 数据控制语言
      • a. 授予
      • b. 撤销
    • 8. DDL 数据定义语言
      • a. 创建表
      • b. 修改表
      • c. 删除表
      • d. 回收站
      • e. Oracle 数据类型
    • 9. DML 数据操作语言
      • a. 新增
      • b. 修改
      • c. 查询
        • i. 伪表 dual
        • ii. 伪列 rowid
        • iii. 伪列 rownum
        • iv. 连接查询
        • v. 组合查询
      • d. 删除
    • 10. TCL 事务控制语言
      • a. 提交
      • b. 保存点与回滚
    • 11. 运算符
      • a. 算术运算符
      • b. 比较(关系)运算符
      • c. 逻辑运算符
      • d. 连接运算符
      • e. 集合运算符
      • f. 运算符优先级
    • 12. 常用函数
      • a. 数值型函数
      • b. 字符型函数
      • c. 日期函数
      • d. 转换函数
      • e. 聚合函数
      • f. 分析函数
      • g. 其它函数
    • 13. 视图
      • a. 视图简介
      • b. 视图操作
    • 14. 同义词
      • a. 私有同义词
      • b. 公有同义词
    • 15. 索引
      • a. 创建索引
      • b. 删除索引
    • 16. 序列
      • a. 创建序列
      • b. 序列使用
      • c. 删除序列
      • d. 序列与 sys_guid
    • 17. 分区表
      • a. 分区表用途
      • b. 分区表类型
        • i. 范围分区
        • ii. 列表分区
    • 18. PL/SQL
      • a. 运算符
      • b. 变量与常量
        • i. 基本类型
        • ii. %type 类型
        • iii. %rowtype 类型
      • c. 控制语句
        • i. 条件语句
        • ii. 循环语句
        • iii. 顺序语句
      • d. 异常处理
        • i. 异常语法
        • ii. 预定义异常
        • iii. 自定义异常
    • 19. 游标
      • a. 显式游标
        • i. 游标语法
        • ii. 游标使用
      • b. 隐式游标
    • 20. 存储过程与存储函数
      • a. 存储过程
        • i. 语法
        • ii. 无参存储过程
        • iii. 有输入参数存储过程
        • iv. 有输出参数存储过程
        • v. 有输入输出参数存储过程
        • vi. 程序中调用存储过程
        • vii. 删除存储过程
      • b. 存储函数
        • i. 语法
        • ii. 无参存储函数
        • iii. 有输入参数存储函数
        • iv. 有输入输出参数存储函数
        • v. 程序中调用存储函数
        • vi. 删除存储函数
      • c. 存储过程与存储函数的区别
    • 21. 程序包
      • a. 简介
      • b. 创建包
        • i. 定义包(包头)
        • ii. 实现包(包体)
        • iii. 应用
        • iv. 程序中调用包
      • c. 删除包
    • 22. 触发器
      • a. 语法
      • b. 行级触发器
      • c. 表级触发器
      • d. 开启禁用触发器
    • 23. 数据字典
    • 24. 角色
      • a. 创建角色
      • b. 删除角色
    • 25. 闪回
      • a. 闪回简介
      • b. 闪回类型
      • c. 闪回查询
      • d. 闪回表
      • e. 闪回删除
    • 26. 数据备份与恢复
      • a. 数据备份
      • b. 数据恢复
    • 27. 性能优化
    • 28. 项目切换到 Oracle 数据库

Oracle

1. Oracle 概述

a. 常见数据库

  • 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。数据库通常分为层次式数据库、网络式数据库和关系式数据库三种;不同的数据库是按不同的数据结构来联系和组织的。将反映和实现数据联系的方法称为数据模型。层次结构模型实质上是一种有根结点的定向有序树,按照层次模型建立的数据库系统称为层次模型数据库系统;按照网状数据结构建立的数据库系统称为网状数据库系统;关系式数据结构把一些复杂的数据结构归结为简单的二元关系(即二维表格形式),由关系数据结构组成的数据库系统被称为关系数据库系统。
  • 数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称 DBMS。它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。用户通过 DBMS 访问数据库中的数据。数据库管理系统是数据库系统的核心,是管理数据库的软件。
  • 常见的关系型数据库有:DB2,Sybase,Oracle,MySQL,Access,MS SQL Server 等。

b. Oracle 简介

  • Oracle 甲骨文公司是第一个跨整个产品线(数据库、业务应用软件和应用软件开发与决策支持工具)开发和部署 100% 基于互联网的企业软件的公司。Oracle 是世界领先的信息管理软件供应商和世界第二大独立软件公司。其主要的有:

    • 数据库服务器:Oracle(9i,10g/11g,12c),MySQL
    • 应用服务器:WegLogic,GlassFish
    • 开发语言:Java
    • 开发集成环境:NetBean
    • Oracle 数据库是当前最主流的数据库之一。

2. Oracle 的组成

a. Oracle 11g 数据库的组成

  • Oracle 的整体架构:
  • 上图示;一般 Oracle 数据库管理系统由:实例和数据库两部分组成。
    • 数据库是一系列物理文件的集合(数据文件,控制文件,联机日志,参数文件等);Oracle 数据库由操作系统文件组成,这些文件也称为数据库文件,为数据库信息提供实际物理存储区。Oracle 数据库包括逻辑结构和物理结构。数据库的物理结构包含数据库中的一组操作系统文件。数据库的逻辑结构是指数据库创建之后形成的逻辑概念之间的关系,如表、视图、索引等对象。
    • 实例则是一组 Oracle 后台进程/线程以及在服务器分配的共享内存区。
  • Oracle 可以创建多个 Oracle 数据库,一个 Oracle 数据库将又由实例和数据库构成。如默认安装时创建的 orcl 数据库外还可再创建其它数据库。创建的数据库将在$OracleHome/oradata/数据库名 目录下以一个个的 *.DBF 文件体现出来。

b. Oracle 11g 数据库服务

  • Oracle * VSS Writer Service – Oracle 卷映射拷贝写入服务,VSS(Volume Shadow Copy Service)能够让存储基础设备(比如磁盘,阵列等)创建高保真的时间点映像,即映射拷贝(shadow copy)。它可以在多卷或者单个卷上创建映射拷贝,同时不会影响到系统的系统能。(非必须启动)
  • OracleDBConsole* – Oracle 数 据 库 控 制 台 服 务 ; 在 运 行 Enterprise Manager(企业管理器 EM)的时候,需要启动这个服务;此服务被默认设置为自动开机启动的(非必须启动)
  • OracleJobScheduler* – Oracle 作业调度服务。此服务被默认设置为禁用状态(非必须启动)
  • OracleMTSRecoveryService – 服务端控制。该服务允许数据库充当一个微软事务服务器 MTS、COM/COM+对象和分布式环境下的事务的资源管理器。恢复、闪回需要开启该服务(非必须启动)
  • OracleOraDb11g_home1ClrAgent – Oracle 数据库.NET 扩展服务的一部分。(非必须启动)
  • OracleOraDb11g_home1TNSListener – 监听器服务,服务只有在数据库需要远程访问或使用 SQL Developer 等工具的时候才需要,此服务被默认的设置为开机启动(非必须启动)
  • OracleService* – 数据库服务,是 Oracle 核心服务该服务,是数据库启动的基础, 只有该服务启动,Oracle 数据库才能正常操作。此服务被默认的设置为开机启动。(必须启动)

3. 连接 Oracle

a. SQL Plus 连接

  • 打开 SQL Plus:
  • 在上述界面中可以输入用户名,如在安装时解锁了的用户 scott,口令为:tiger
  • 输入语句查询该用户下的对象:
  • 另外;也可以直接在命令行中输入 sqlplus scott/tiger 进入并登录

b. SQL Developer 连接

  • 打开 SQL Developer ;在出现界面的左边右击鼠标,新建连接:

  • 注意在上图中;
    • 主机名:如果是本机的按照配置在网络管理中的服务的配置设置,可以为 localhost;如果是连接其它机器的数据库则指定其 ip;
    • SID:是指定数据库服务器上的全局数据库名称,默认安装的话一般是 orcl

c. PLSQL Developer 连接

  • 安装 PLSQL Develper;见《PLSQL Developer 安装及注册.docx》

d. Jdbc 连接

  1. 在安装目录下找到 Oracle 的驱动包;
    如下路径可以找到 Oracle 的驱动包:
    C:\Oracle11g\product\11.2.0\dbhome_1\jdbc\lib 复制 ojdbc6.jar 到项目中进行连接测试;
  2. 新建 Java 项目测试连接;

4. SQL Plus 设置与常用命令

a. 显示设置

-- 设置每行显示的最长字符数
set linesize 120
-- 设置一页显示的行数
set pagesize 20
-- 设置是否显示一页的记录数
set feedback on/off
-- 打开或取消Oracle自带的输出方法dbms_output,并输出内容
set serveroutput on/off
-- 格式化列的内容:将列名对应的列的值格式化为四位数值长度
col 表中对应的列名 for 9999
column 表中对应的列名 format 9999
【示例】
-- 表明将 empno 列名对应的列值格式为 4 位长度的数值型
col empno for 9999
-- 格式化列的内容:将列名对应的列的值格式化为10位字母长度
col 表中对应的列名 for a10
【示例】
-- 表明将ename列名对应的列值格式为10位长度的字符型
col ename for a10

b. 常用命令

命令 说明
show all 查看系统所有变量值
show user 显示当前连接用户
conn 切换用户,连接系统
desc 表名 显示表的结构;如:desc emp
/* */ 多行注释
单行注释
/ 执行缓冲区中的语句
ed 打开默认编辑器,Windows 系统中默认是 notepad.exe,把缓冲区中最后一条 SQL 语句调入 afiedt.buf 文件中进行编辑(如果提示没有afiedt.buf 请使用管理员身份打 开 SLQ Plus);常用于语句比较长需要修改时。
spool文件地址

spool 文件地址 append

spool off

假脱机命令;将命令行的内容(从设置后开始的命令行内容)记录到文本。添加 append 的意思是在原有的文本内容上追加后续的命令行的内容;需要注意的是所有的这些内容都将在 spool off 之后才记录。如:
spool d:\regino\regino.txt
spool d:\regino\test.sql append
spool off
clear screen 或者 host cls 清屏
exit 退出 SQL Plus

5. 表空间

  • 表空间是数据库中最大的逻辑单位,Oracle 数据库采用表空间将相关的逻辑组件组合在一起,一个 Oracle 数据库至少包含一个表空间。每个表空间由一个或多个数据文件组成,一个数据文件只能与一个表空间相联系。
  • 在每一个数据库中都有一个名为 SYSTEM 的表空间,即系统表空间,该表空间是在创建数据库或数据库安装时自动创建的,用于存储系统的数据字典表、程序单元、过程、函数、包和触发器等。

a. 表空间类型

  • 永久性表空间:一般保存表、视图、过程和索引等的数据
  • 临时性表空间:只用于保存系统中短期活动的数据
  • 撤销表空间:用来帮助回退未提交的事务数据

b. 操作与运用

  • 创建表空间
【语法】
CREATE TABLESPACE 表空间名DATAFILE '数据文件路径' SIZE 大小[AUTOEXTEND ON] [NEXT 大小][MAXSIZE 大小];【说明】
[]里面内容可选项;数据文件路径中若包含目录需要先创建
SIZE 为初始表空间大小,单位为 K 或者 M
AUTOEXTEND ON 是否自动扩展
NEXT 为文件满了后扩展大小
MAXSIZE 为文件最大大小,值为数值或 UNLIMITED(表示不限大小)【示例】
CREATE TABLESPACE regino_tsDATAFILE 'd:\Oracle_data\regino01.dbf' SIZE 10MAUTOEXTEND ON;
  • 查询表空间
--管理员角色查看表空间
SELECT file_name,tablespace_name,bytes,autoextensible
FROM dba_data_files
WHERE tablespace_name='regino_TS';
  • 修改表空间
【语法】
ALTER TABLESPACE 表空间名ADD DATAFILE '文件路径' SIZE 大小[AUTOEXTEND ON] [NEXT 大小][MAXSIZE 大小];【示例】
ALTER TABLESPACE regino_tsADD DATAFILE 'd:\Oracle_data\regino02.DBF' SIZE 5MAUTOEXTEND ON;
  • 删除表空间
【语法】
DROP TABLESPACE 表空间名;
DROP TABLESPACE 表空间名 INCLUDING CONTENTS AND DATAFILES;【说明】
第一个删除语句只删除表空间;第二个删除语句则删除表空间及数据文件【示例】
DROP TABLESPACE regino_ts;
DROP TABLESPACE regino_ts INCLUDING CONTENTS AND DATAFILES;

6. 数据库用户

a. 系统常见用户

用户 说明
sys 超级用户,主要用来维护系统信息和管理实例,以 SYSDBA 或 SYSOPER 角色登录。密 码为在安装时设置的管理口令,如一般设置为:orcl
system 默认的系统管理员,拥有 DBA 权限,通常用来管理 Oracle 数据库的用户、权限和存储,以 Normal 方式登录。密码为在安装时设置的管理口令,如一般设置为:orcl
scott 示范用户,使用 users 表空间。一般该用户默认密码为 tiger

b. 用户管理

  • Oracle 中有个模式(schema)的概念,它是用户的所有数据库对象的集合;一般在创建用户的同时会自动创建一个这样的模式,名称和用户名称一样。模式(schema)是对用户所创建的数据库对象的总称,在 Oracle 数据库中任何数据库对象都属于一个特定用户,一个用户及其所拥有的对象即称为模式。模式对象包括表、视图、索引、同义词、序列、过程和程序包等。一个用户与相同名称的模式相关联,所以又称为用户模式。
  • 查询系统用户
select * from all_users;
或
select * from dba_users; --更详细的用户信息
  • 解锁用户
【语法】
ALTER USER 用户名 ACCOUNT UNLOCK;【示例】解锁 hr 用户
alter user hr account unlock;
  • 创建用户
【语法】
CREATE USER 用户名 IDENTIFIED BY 密码DEFAULT TABLESPACE 表空间;【示例】
CREATE USER regino IDENTIFIED BY reginoDEFAULT TABLESPACE regino_tsTEMPORARY TABLESPACE temp;
  • 修改用户密码
【语法】
ALTER USER 用户名 identified by 密码【示例】
ALTER USER regino identified by it;
  • 删除用户
【语法】
DROP USER 用户名 CASCADE;【示例】
DROP USER regino CASCADE;

7. DCL 数据控制语言

a. 授予

【语法 1】
GRANT 角色权限(角色)[,角色权限] TO 用户;【示例 1】
--授予CONNECT和RESOURCE两个角色
GRANT connect, resource TO regino;【备注】使用如下语句可以查看 resource 角色下的权限
SELECT * FROM DBA_SYS_PRIVS WHERE GRANTEE='RESOURCE'【语法 2】
GRANT 操作 ON 模式.对象 TO 用户;【示例 2】
--允许用户查看、更新 EMP 表中的记录
GRANT select,update ON SCOTT.emp TO regino;
--查看当前用户的系统权限
select * from user_sys_privs;
--查看当前用户的对象权限
select * from user_tab_privs;
--查看当前用户的所有角色
select * from user_role_privs;

b. 撤销

【语法 1】
REVOKE 角色权限(角色)[,角色权限] FROM 用户;【示例 1】
--撤销CONNECT和RESOURCE两个角色
REVOKE connect, resource FROM regino;【语法 2】
REVOKE 操作 ON 模式.对象 FROM 用户;【示例 2】
--撤销用户查看、更新 EMP 表中的记录的操作
REVOKE select,update ON SCOTT.emp FROM regino;

8. DDL 数据定义语言

a. 创建表

【语法】
CREATE TABLE <table_name>(
column1 DATATYPE [NOT NULL] [PRIMARY KEY],
column2 DATATYPE [NOT NULL],
...
[constraint <约束名> 约束类型 (要约束的字段)
... ] );【说明】
DATATYPE --是 Oracle 的数据类型
NUT NULL --可不可以允许资料有空的(尚未有资料填入)
PRIMARY KEY --是本表的主键
constraint --是对表里的字段添加约束.(约束类型有Check,Unique,Primary key,not null,Foreign key);【示例】
create table t_student(
s_id number(8) PRIMARY KEY,
s_name varchar2(20) not null,
s_sex varchar2(8),
clsid number(8),
constraint u_1 unique(s_name),
constraint c_1 check (s_sex in ('MALE','FEMALE'))
);
--从现有的表创建表及复制其数据【语法】
CREATE TABLE <table_name> as <SELECT 语句>【示例】
create table emp as select * from scott.emp;
create table emp as select empno,ename from scott.emp --表结构只有
empno 和 ename 两个字段及该两字段对应的数据
--如果只复制表的结构不复制表的数据则:
create table emp as select * from scott.emp where 1=2;

b. 修改表

【语法 1】向表中添加新字段
ALTER TABLE <table_name> ADD (字段 1 类型 [NOT NULL],
字段 2 类型 [NOT NULL] ... );【示例 1】
alter table t_student add (s_age number(3),s_address varchar2(20));【语法 2】修改表中字段
ALTER TABLE <table_name> MODIFY(字段 1 类型,字段 2 类型 ... );【示例 2】
alter table t_student modify(s_name varchar2(50),s_address
varchar2(100));【语法 3】删除表中字段
ALTER TABLE <table_name> DROP(字段 1,字段 2... );【示例 3】
alter table t_student drop(s_age,s_address);【语法 4】修改表字段名称
ALTER TABLE <table_name> RENAME COLUMN 原字段名称 TO 新字段名称;【示例 4】
alter table t_student rename column s_id to s_no;

c. 删除表

【语法 1】 --删除表结构及数据(删除后可在回收站查看并恢复)
DROP TABLE <table_name>;
--删除表结构及数据(删除后不可在回收站查看并恢复)
DROP TABLE <table_name> PURGE;【示例 1】
drop table t_student;

d. 回收站

  • 查看回收站
--查看回收站
show recyclebin; 或 select * from recyclebin;
  • 清空回收站
--清空回收站
purge recyclebin;

e. Oracle 数据类型

数据类型 描述
VARCHAR2(size) 可变长度的字符串,其最大长度为 size 个字节;size 的最大值是 4000,而最小值是 1;你必须指定一个 VARCHAR2 的 size;
NVARCHAR2(size) 可变长度的字符串,依据所选的国家字符集,其最大长度为 size 个字符或字节;size 的最大值取决于储存每个字符所需的字节数,其上限为 4000;你必须指定一个 NVARCHAR2 的 size;
NUMBER(p,s) 精度为 p 并且数值范围为 s 的数值;精度 p 的范围从 1 到 38;数值范围 s 的范围是从-84 到 127;例如:NUMBER(5,2) 表示整数部分最大 3 位,小数部分为 2 位;NUMBER(5,-2) 表示数的整数部分最大为 7 其中对整数的倒数 2 位为 0,前面的取整。NUMBER 表示使用默认值,即等同于 NUMBER(5);
LONG 可变长度的字符数据,其长度可达 2G 个字节;
DATE 有效日期范围从公元前 4712 年 1 月 1 日到公元后 9999 年 12 月 31 日
TIMESTAMP date 和 timestamp 都是对日期和时间的表示,只是两种类型的精确度不同,前者精确到秒,后者精确到小数秒(fractional_seconds_precision),可以是 0 to 9,缺省是 6
RAW(size) 长度为 size 字节的原始二进制数据,size 的最大值为 2000 字节;你必须为 RAW 指定一个 size;
LONG RAW 可变长度的原始二进制数据,其最长可达 2G 字节;
CHAR(size) 固定长度的字符数据,其长度为 size 个字节;size 的最大值是 2000 字节,而最小值和默认值是 1;
NCHAR(size) 也是固定长度。根据 Unicode 标准定义
CLOB 一个字符大型对象,可容纳单字节的字符;不支持宽度不等的字符集;最大为 4G 字节
NCLOB 一个字符大型对象,可容纳单字节的字符;不支持宽度不等的字符集;最大为 4G 字节;储存国家字符集
BLOB 一个二进制大型对象;最大 4G 字节
BFILE 包含一个大型二进制文件的定位器,其储存在数据库的外面;使得可以以字符流 I/O 访问存在数据库服务器上的外部 LOB;最大大小为 4G 字节.

9. DML 数据操作语言

a. 新增

【语法 1】
INSERT INTO table_name (column1,column2,...)
VALUES ( value1,value2, ...);【示例 1】
insert into emp (empno,ename) values(1111,'regino');【语法 2】
INSERT INTO <table_name> <SELECT 语句>;【示例 2】
create table t1 as select * from emp where 1=2;
insert into t1 select * from emp where sal>2000;

b. 修改

【语法 1】
UPDATE table_name SET column1=new value,column2=new value,...
WHERE <条件>;【示例 1】
update emp set sal=3000 where ename='regino';

c. 查询

i. 伪表 dual

  • DUAL 是一个虚拟表,用来构成 select 的语法规则,Oracle 保证 dual 里面永远只有一条记录。以用它来做很多事情,如:
  • 查看当前用户
select user from dual;
  • 用来调用系统函数
--查询系统的当前时间并格式化
select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
  • 得到序列的下一个值或当前值
--获得序列seq的下一个值
select seq.nextval from dual;
--获得序列seq的当前值
select seq.currval from dual;
  • 可以用做计算器
select 2*8 from dual;

ii. 伪列 rowid

  • rowid 是物理结构上的,在每条记录 insert 到数据库中时,都会有一个唯一的物理记录,同一条记录在不同查询中对应的 rowid 相同。
【用法】
SELECT ROWID,字段名... FROM 表名; 【示例】
select rowid, emp.* from emp;

iii. 伪列 rownum

  • rownum 是根据 sql 查询出的结果给每行分配一个逻辑编号;每次的查询都会有不同的编号。编号从 1 开始。
【用法】
SELECT ROWNUM,字段名... FROM 表名;【注意】
ROWNUM 不能使用大于号“>” 即 select rownum, emp.* from emp where rownum > 2 是不对的,没有任何
结果【示例】
select rownum, emp.* from emp;
/* 关于分页:由于不能使用>,所以为了达到分页目的得如下执行;如获取第
2 页数据(每页 3 条)*/
select * from (select rownum r,emp.* from emp where rownum < 7) where
r > 3;
/* 关于排序:由于 rownum 是查询结果的行编号,排序后这个编号便有可能被
打乱,如果需要该编号和排序的结果列表序号保持一致可以如下执行*/
select rownum,t.* from (select empno,ename from emp order by empno
desc) t;

iv. 连接查询

  • 准备查询数据,将 scott 用户下的 dept 表复制到 regino 用户下。
使用 sys 用户登录系统;替 regino 用户创建 dept 表,表结构和数据来自 scott.dept。
--执行语句如下
create table regino.dept as select * from scott.dept;
  • 等值查询
--查询emp表中各用户对应的部门名称
select empno,ename,dname from emp,dept where
emp.deptno=dept.deptno;
--练习:按部门统计员工的人数,要求显示部门号、部门名称、和部门人数
select d.deptno,d.dname,count(e.empno) from dept d,emp e
where d.deptno=e.deptno
group by d.deptno,d.dname;
  • 左外/右外连接查询:左外连接是在等号左边的集合,无论条件是否成立均在结果集合,写法就是在等号右边使用(+),这个写法是 Oracle 专用的,如果需要全数据库类型通用应该使用 left join)
--按部门统计员工的人数,要求显示部门号、部门名称、和部门人数,部门
下没有人的也将显示
select d.deptno,d.dname,count(e.empno) from dept d,emp e
where d.deptno=e.deptno(+) group by d.deptno,d.dname;
--上述语句的通用数据库写法(left join方式)
select d.deptno,d.dname,count(e.empno) from dept d left join emp e
on d.deptno=e.deptno group by d.deptno,d.dname;
  • 自连接查询:查询的 2 张表是同一张表,一般是该表的字段之间存在上下级关系
--查询员工和老板的上下级关系
select e.ename || ' 的老板是: '|| b.ename from emp e,emp b
where e.mgr=b.empno; 【注意】上述查询语句中的||表示为字符的连接

v. 组合查询

  • 计算部门工资总和,最高工资,最低工资
select deptno,sum(sal),max(sal),min(sal) from emp group by deptno;
  • 部门平均工资
--查询部门的平均工资
select deptno,avg(sal) from emp group by deptno;
--查询平均工资大于2000的部门,并按照平均工资降序排序
select deptno,avg(sal) 平均工资 from emp
group by deptno
having avg(sal)>2000
order by 平均工资 desc ;
--查询除了20部门以外,平均工资大于2000的部门
select deptno,avg(sal) from emp
where deptno <> 20
group by deptno
having avg(sal)>2000; 【注意】SQL 语句中的各子句执行顺序:
from->where->group by->having->select->order by
  • 子查询:将子查询放入括号中;group by 后不能使用子查询;select、from、where 后面都可以使用子查询;可以将子查询看作一张新表
--select后面的子查询
select (select dname from dept where deptno=10),ename from emp
where deptno=10;
--from后面的子查询
select * from (select ename,sal from emp);
--将子查询视为一个表
select e.ename,e.sal from (select ename,sal from emp) e;
--where后面的子查询;查询工资比10号部门员工中任意一个员工的工资低的员工信息
select * from emp where sal < (select min(sal) from emp where
deptno=10);
  • 其它查询
--查询姓名是5个字符的员工,且第二个字符是C,使用_只匹配一个字符并且不能标识0或多个字符
select * from emp where ename like '_C___';
--查询员工姓名中含有‘_’的员工,使用\转义字符
select * from emp where ename like '%\_%' escape '\';

d. 删除

--根据条件删除表数据
delete from emp where empno=0000
--清空表数据(表还在),不写日志,省资源,效率高,属于数据定义语言
--先创建要清空数据的表
create table myemp as select * from emp;
--清空表数据
truncate table myemp;

10. TCL 事务控制语言

a. 提交

  • 事务的提交比较简单;直接在执行 DML 语句后进行提交即可,如果不提交事务则刚刚通过 DML 语句进行修改的内容还未保存到数据库中,只在当前用户的连接会话中有效。要永久变更数据需要显示地执行提交、回滚或者退出当前回话(如退出 sqlplus)。
  • 提交的命令为:commit;

b. 保存点与回滚

  • 保存点 savepoint 一般与回滚 rollback 配合使用。在设置了 savepoint 后事务的粒度可以控制的更加细化,可以回滚到特定的保存点。
【语法】保存点 savepoint
SAVEPOINT <savepoint_name>;【示例】
--创建一个保存点,名称为 a
savepoint a;【注意】当创建保存点之后执行的 DML 操作,可以进行回滚,而保存点之前未
提交的 DML 操作不受影响。【语法】回滚
ROLLBACK [TO savepoint];【示例】
--回滚到保存点 a,即在保存点 a 之后的所有未提交的 DML 都无效。
rollback to a;/*保存点与回滚完整示例*/
--1、创建保存点a
savepoint a;
--2、插入emp数据 it1
insert into emp(empno,ename) values(1234,'it1');
--3、创建保存点b
savepoint b;
--4、插入emp数据 it2
insert into emp(empno,ename) values(1235,'it2');
--5、查看emp表数据,存在it1、it2两条数据
select ename from emp;
--6、回滚到保存点b,即it2数据将消失
rollback to b;
--7、查看emp表数据,存在it1的数据,it2已不在
select ename from emp;
--8、提交数据
commit;
--9、查看emp表数据,存在it1的数据
select ename from emp;
--10、回滚到保存点a,将报错保存点不存在的错误信息
rollback to a;

11. 运算符

a. 算术运算符

  • +、-、*、/

b. 比较(关系)运算符

  • =、!=、<>、< 、 > 、 <= 、 >= 、 between…and… 、in 、like
    、is null

c. 逻辑运算符

  • AND(逻辑与),表示两个条件必须同时满足
  • OR(逻辑或),表示两个条件中有一个条件满足即可
  • NOT(逻辑非),返回与某条件相反的结果

d. 连接运算符

  • ||
【示例】
select '工号为:' || empno || ' 的员工的姓名为:'|| ename from emp;

e. 集合运算符

  • union(并集无重复)
  • union all(并集有重复)
  • intersect(交集,共有部分)
  • minus(减集,第一个查询具有,第二个查询不具有的数据)
【注意】:列数相关,对应列的数据类型兼容,不能含有 Long 类型的列,第一个 select 语句的列或别名作为结果标题--union(并集将去重复)
select * from emp where deptno=10
union
select * from emp where deptno=20;
--intersect(交集) 查询工资即属于1000~2000区间和1500~2500区间的工资
select ename,sal from emp where sal between 1000 and 2000
intersect
select ename,sal from emp where sal between 1500 and 2500;
--minus(减集)
select ename,sal from emp where sal between 1000 and 2000
minus
select ename,sal from emp where sal between 1500 and 2500;

f. 运算符优先级

优先级 运算符
1 算术运算符
2 连接符
3 比较符
4 IS[NOT]NULL, LIKE, [NOT]IN
5 [NOT] BETWEEN
6 NOT
7 AND
8 OR
  • 可以使用括号改变优先级顺序;OR 的优先级最低,算术运算符的优先级最高。

12. 常用函数

a. 数值型函数

  • round(x[,y])
【功能】返回四舍五入后的值【参数】x,y,数字型表达式,如果 y 不为整数则截取 y 整数部分,如果 y>0 则四舍五入为 y 位小数,如果 y 小于 0 则四舍五入到小数点向左第 y 位。【返回】数字【示例】
select round(5555.6666,2.1),round(5555.6666,-2.6),round(5555.6666)
from dual;返回: 5555.67 , 5600 , 5556
  • trunc(x[,y])
【功能】返回 x 按精度 y 截取后的值【参数】x,y,数字型表达式,如果 y 不为整数则截取 y 整数部分,如果 y>0 则截取到 y 位小数,如果 y 小于 0 则截取到小数点向左第 y 位,小数前其它数据用 0 表示。【返回】数字【示例】
select trunc(5555.66666,2.1),
trunc(5555.66666,-2.6),trunc(5555.033333) from dual;返回:5555.66 5500 5555

b. 字符型函数

  • LENGTH(c1)
【功能】返回字符串的长度;【说明】多字节符(汉字、全角符等),按 1 个字符计算【参数】C1 字符串【返回】数值型【示例】
select length('个人博客'),length('regino 个人博客') from dual;LENGTH('个人博客') LENGTH('regino 个人博客')
------------------ ------------------------4 10
  • LPAD(c1,n[,c2])、RPAD(c1,n[,c2])
【功能】在字符串 c1 的左(右)边用字符串 c2 填充,直到长度为 n 时为止【说明】如果 c1 长度大于 n,则返回 c1 左边 n 个字符【参数】C1 字符串n 追加后字符总长度c2 追加字符串,默认为空格【返回】字符型【示例】
select lpad('regino',10,'*'),rpad('regino',10,'*') from dual;
  • REPLACE(c1,c2[,c3])
【功能】将字符表达式值中,部分相同字符串,替换成新的字符串【参数】c1 希望被替换的字符或变量c2 被替换的字符串c3 要替换的字符串,默认为空(即删除之意,不是空格)【返回】字符型【示例】
select replace('he love you','he','i') from dual;
  • SUBSTR(c1,n1[,n2])
【功能】取子字符串【说明】多字节符(汉字、全角符等),按 1 个字符计算【参数】在字符表达式 c1 里,从 n1 开始取 n2 个字符;若不指定 n2,则从第 n1 个字符直到结束的字串.
【返回】字符型【示例】
select substr('123456789',4,4),substr('123456789',3) from dual;

c. 日期函数

  • sysdate
【功能】:返回当前日期。
【参数】:没有参数,没有括号
【返回】:日期【示例】select sysdate from dual;
  • add_months(d1,n1)
【功能】:返回在日期 d1 基础上再加 n1 个月后新的日期。
【参数】:d1,日期型,n1 数字型
【返回】:日期【示例】select sysdate,add_months(sysdate,3) from dual;
  • months_between(d1,d2)
【功能】:返回日期 d1 到日期 d2 之间的月数。
【参数】:d1,d2 日期型
【返回】:数字
如果 d1>d2,则返回正数
如果 d1<d2,则返回负数【示例】
select sysdate,
months_between(sysdate,to_date('2015-01-01','YYYY-MM-DD')) 距2015元 旦,
months_between(sysdate,to_date('2016-01-01','YYYY-MM-DD')) 距2016元 旦 from dual;
  • extract(c1 from d1)
【功能】:日期/时间 d1 中,参数(c1)的值
【参数】:d1 日期型(date)/日期时间型(timestamp),c1 为字符型(参数)
【参数表】:c1 对应的参数表详见示例
【返回】:字符【示例】
select
extract(YEAR from timestamp '2015-5-1 12:26:18 ' ) 年,
extract(MONTH from timestamp '2015-5-1 12:26:18 ' ) 月,
extract(DAY from timestamp '2015-1-5 12:26:18 ' ) 日,
extract(hour from timestamp '2015-5-1 12:26:18 ' ) 小时,
extract(minute from timestamp '2015-5-1 12:26:18' ) 分钟,
extract(second from timestamp '2015-5-1 12:26:18 ' ) 秒
from dual;
select extract (YEAR from date '2015-5-1' ) from dual;
select sysdate 当前日期,
extract(YEAR from sysdate ) 年,
extract(MONTH from sysdate ) 月,
extract(DAY from sysdate ) 日
from dual;
--如下语句也可获取年份、月份等
select to_number(to_char(sysdate,'yyyy')) from dual;

d. 转换函数

  • TO_CHAR(x[[,c2],C3])
【功能】将日期或数据转换为 char 数据类型
【参数】x 是一个 date 或 number 数据类型。c2 为格式参数c3 为 NLS 设置参数
【返回】varchar2 字符型【示例】
select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') FROM dual;
select to_char(1210.7, '$9,999.00') FROM dual;
  • TO_DATE(X[,c2[,c3]])
【功能】将字符串 X 转化为日期型
【参数】c2,c3,字符型,参照 to_char()
【返回】字符串
如果 x 格式为日期型(date)格式时,则相同表达:date x
如果 x 格式为日期时间型(timestamp)格式时,则相同表达:timestamp x【示例】
select to_date('201212','yyyymm'),
to_date('2012.12.20','yyyy.mm.dd'),
(date '2012-12-20') XXdate,
to_date('2012-12-20 12:31:30','yyyy-mm-dd hh24:mi:ss'),
to_timestamp('2012-12-20 12:31:30','yyyy-mm-dd hh24:mi:ss'),
(timestamp '2012-12-20 12:31:30') XXtimestamp
from dual;
  • TO_NUMBER(X[[,c2],c3])
【功能】将字符串 X 转化为数字型
【参数】c2,c3,字符型
【返回】数字串【示例】
select TO_NUMBER('201212') + 3,TO_NUMBER('450.05') + 1 from dual;
--等同上述结果
select '201212' + 3 from dual;

e. 聚合函数

  • sum:求和
  • avg:求平均数
  • count:计数
  • max:求最大值
  • min:求最小值

f. 分析函数

  • 分析函数中了解 rank()/dense_rank()/row_number() 的使用:
--查询部门的员工工种情况,并在部门内重新进行排序;PARTITION BY类似
group by,根据ORDER BY排序字段的值重新由1开始排序。
--RANK 使用相同排序排名一样,后继数据空出排名;即有2个排序为1的,那么接下来的排序号则为3
select deptno,ename,job,rank() over(partition by deptno order by
job) as myRank from emp e;
--DENSE_RANK使用,使用相同排序排名一样,后继数据不空出排名;即有2个排序为1的,那么接下来的排序号则为2
select deptno,ename,job,dense_rank() over(partition by deptno order
by job) as myDenseRank from emp e;
--ROW_NUMBER使用,不管排名是否一样,都按顺序排名;即有2个排序为1的,那么排序号不会重现重复
select deptno,ename,job,row_number() over(partition by deptno order
by job) as myRowNumber from emp e;

g. 其它函数

  • NVL()/NVL2()
【语法】NVL (expr1, expr2)
【功能】若 expr1 为 NULL,返回 expr2;expr1 不为 NULL,返回 expr1。注意两者的类型要一致【示例】将员工的奖金如果是空的话则设置为 0
select ename,sal,comm,nvl(comm,0) from emp;【语法】NVL2 (expr1, expr2, expr3)
【功能】expr1 不为 NULL,返回 expr2;expr2 为 NULL,返回 expr3。expr2 和 expr3 类型不同的话,expr3 会转换为 expr2 的类型【示例】
select ename,job,nvl2(job,'job 有值','job 无值') from emp;
  • decode(条件,值 1,翻译值 1,值 2,翻译值 2,…值 n,翻译值 n,缺省值)
【功能】根据条件返回相应值
【参数】c1, c2, ...,cn,字符型/数值型/日期型,必须类型相同或 null
注:值 1……n 不能为条件表达式,这种情况只能用 case when then end 解决含义解释: decode(条件,值 1,翻译值 1,值 2,翻译值 2,...值 n,翻译值 n,缺省值) 该函数的含义如下: IF 条件=值 1 THENRETURN(翻译值 1)ELSIF 条件=值 2 THENRETURN(翻译值 2)......ELSIF 条件=值 n THENRETURN(翻译值 n) ELSERETURN(缺省值)END IF【示例】根据员工的部门号,条件判断找到对应的部门名称
select ename,deptno,decode(deptno,10,'ACCOUNTING',20,'RESEARCH',30,'SALES'
,'无部门') from emp;

13. 视图

a. 视图简介

  • 视图是由一个或者多个表组成的虚拟表;那些用于产生视图的表叫做该视图的基表。视图不占用物理空间,这个也是相对概念,因为视图本身的定义语句还是要存储在数据字典里的。视图只有逻辑定义。每次使用的时候只是重新执行 SQL。一个视图也可以从另一个视图中产生。视图没有存储真正的数据,真正的数据还是存储在基表中。一般出于对基本的安全性和常用的查询语句会建立视图;并一般情况下不对视图进行新增、更新操作。
【语法】
--创建视图
CREATE [OR REPLACE] VIEW <view_name>
AS
<SELECT 语句>;--删除视图
DROP VIEW <view_name> ;

b. 视图操作

-- 授予regino用户 创建视图 的权限
grant create view to regino;-- 登录regino,创建视图
create or replace view v_emp
as
select empno,ename from emp;--通过视图查询数据
select * from v_emp;--通过视图添加数据,需要保证基表的其它数据项可以为空
insert into v_emp(empno,ename) values(3333,'regino3');--通过视图修改数据
update v_emp set ename='个人博客3' where empno=3333;--通过视图删除数据
delete from v_emp where empno=3333;--基于多个基表的视图,不建议使用视图进行增删改操作
create or replace view v_dept_emp
as
select dept.deptno,dept.dname,ename from emp inner join dept on emp.deptno=dept.deptno;--查询多个基表的视图
select * from v_dept_emp;--创建基于视图的视图
create or replace view vv_emp
as
select ename from v_emp;--查询基于视图的视图
select * from vv_emp;--删除视图
drop view v_emp;
drop view v_dept_emp;
drop view vv_emp;

14. 同义词

  • 同义词是数据库模式对象的一个别名,经常用于简化对象访问和提高对象访问的安全性。在使用同义词时,Oracle 数据库将它翻译成对应模式对象的名字。与视图类似,同义词并不占用实际存储空间,只有在数据字典中保存了同义词的定义。在 Oracle 数据库中的大部分数据库对象,如表、视图、同义词、序列、存储过程等,数据库管理员都可以根据实际情况为他们定义同义词。隐藏对象名称和所有者。

a. 私有同义词

  • 私有 Oracle 同义词由创建它的用户所有;创建的用户需要具有 CREATE SYNONYM 权限。
【语法】
CREATE SYNONYM <synonym_name> for <tablename/viewname...>【示例】
--管理员 授权用户regino创建同义词的权限
grant create synonym to regino;
--创建私有同义词
create synonym syn_emp for emp;
create synonym syn_v_emp for v_emp;--为视图v_emp创建私有同义词(别
名)
--使用私有同义词
select empno,ename from syn_emp;
update syn_emp set ename='regino5' where empno='1234';
--删除同义词
drop synonym syn_emp;

b. 公有同义词

  • 公有 Oracle 同义词由一个特殊的用户组 Public 所拥有。顾名思义,数据库中所有的用户都可以使用公有同义词。公有同义词往往用来标示一些比较普通的数据库对象,这些对象常需要引用。公有同义词一般由管理员用户创建及删除,普通用户需要创建及删除需要 create public synonym 和 drop public synonym 权限。
【语法】
CREATE PUBLIC SYNONYM <synonym_name> for <tablename/viewname...>
--登陆sys管理员用户,授权用户regino创建、删除(公有的删除权限需要特别给定)公有同义词权限
grant create public synonym,drop public synonym to regino;
--revoke create public synonym,drop public synonym from regino;--登陆regino用户创建公有同义词 conn regino/regino;
create public synonym syn_public_emp for emp;--使用公有同义词
select * from syn_public_emp;-- 登录system管理员 conn system/orcl; 创建regino2并授权
--create user regino2 identified by regino2 default tablespace
regino_ts;
--grant connect,resource to regino2;--为其它用户regino2授权使用公有同义词(需要给予使用表的权限)
grant select,update on regino.emp to regino2;
--revoke select,update on regino.emp from regino2;--登陆regino2用户下使用公有同义词syn_public_emp
select * from syn_public_emp;
update syn_public_emp set ename='个人博客5' where empno=5555;--删除同义词
--登陆regino,删除公有同义词
drop public synonym syn_public_emp;

15. 索引

  • 索引是建立在数据库表中的某些列的上面,是与表关联的,可提供快速访问数据方式,但会影响增删改的效率;常用类型(按逻辑分类):单列索引和组合索引、唯一索引和非唯一索引。
  • 什么时候要创建索引
    (1)在经常需要搜索、主键、连接的列上
    (2)表很大,记录内容分布范围很广
    (3)在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的
    (4)在经常使用在 WHERE 子句中的列上面创建索引
  • 什么时候不要创建索引
    (1)表经常进行 INSERT/UPDATE/DELETE 操作
    (2)表很小(记录超少)
    (3)列名不经常作为连接条件或出现在 WHERE 子句中
    (4)对于那些定义为 text, image 和 bit 数据类型的列不应该增加索引

a. 创建索引

【语法】
CREATE [UNIQUE] INDEX <index_name> ON <table_name>(字段 [ASC|DESC]);【说明】
UNIQUE --确保所有的索引列中的值都是可以区分的。
[ASC|DESC] --在列上按指定排序创建索引。(创建索引的准则:
1.如果表里有几百行记录则可以对其创建索引(表里的记录行数越多索引的效
果就越明显)。
2.不要试图对表创建两个或三个以上的索引。
3.为频繁使用的行创建索引。) 【示例】
--创建单列唯一索引,表中的列值将不允许重复
create unique index index_emp_empno on emp(empno);
--创建单列非唯一索引
create index index_emp_ename on emp(ename);
--创建组合列、唯一索引
create unique index index_emp_ename_job on emp(ename,job);
--创建组合列、非唯一索引
create index index_emp_job_sal on emp(job,sal);

b. 删除索引

【语法】
DROP INDEX <index_name>;【示例】
--删除索引
drop index index_emp_empno;
drop index index_emp_ename;
drop index index_emp_ename_job;
drop index index_emp_job_sal;

16. 序列

  • 序列是 Oracle 提供的一个产生唯一数值型值的机制。通常用于表的主健值,序列只能保证唯一,不能保证连续。

a. 创建序列

【语法】
CREATE SEQUENCE <sequencen_name>
[INCREMENT BY n]
[START WITH n]
[MAXVALUE n][MINVALUE n]
[CYCLE|NOCYCLE]
[CACHE n|NOCACHE];INCREMENT BY n --表示序列每次增长的幅度;默认值为 1.
START WITH n --表示序列开始时的序列号。默认值为 1.
MAXVALUE n --表示序列可以生成的最大值(升序).
MINVALUE n --表示序列可以生成的最小值(降序).
CYCLE --表示序列到达最大值后,在重新开始生成序列.默认值为 NOCYCLE。
CACHE n--允许更快的生成序列.预先生成 n 个序列值到内存(如果没有使用
完,那下次序列的值从内存最大值之后开始;所以 n 不应该设置太大)【示例】
--创建递增序列
create sequence seq_test
increment by 1
start with 1
maxvalue 1000
nocycle;--创建递减序列
create sequence seq_test2
increment by -1
start with 5
maxvalue 5
minvalue 1
nocycle;

b. 序列使用

  • NEXTVAL 返回序列下一个值;第一次访问时,返回序列的初始值,后继每次调用时,按步长增加的值返回
【语法】
select <sequence_name>.nextval from dual;【示例】
select seq_test.nextval from dual;
  • CURRVAL 返回序列的当前值.注意在刚建立序列后,序列的 CURRVAL 值为 NULL,所以不能直接使用。使用过 NEXTVAL 访问序列后才能使用
【语法】查看序列的当前值
select <sequence_name>.currval from dual;【示例】
select seq_test.nextval from dual;
select seq_test.currval from dual;
  • 运用序列
-- 创建序列
create sequence seq_emp_empno
start with 1000
increment by 1
maxvalue 9000
minvalue 1000
nocycle;-- 使用序列作为主键插入emp表的empno列
insert into emp(empno,ename)
values(seq_emp_empno.nextval,'regino1');
insert into emp(empno,ename)
values(seq_emp_empno.nextval,'regino2');-- 查看emp表数据
select empno,ename from emp;-- 查看当前序列的值
select seq_emp_empno.currval from dual;--修改序列
alter sequence seq_emp_empno
maxvalue 9999
cycle;

c. 删除序列

【语法】
DROP SEQUENCE <sequence_name> 【示例】
drop sequence seq_test;

d. 序列与 sys_guid

  • sys_guid 和序列都可以作为主键值。
--使用SYS_GUID函数,32位,由时间戳和机器标识符生成,保证唯一
select sys_guid() from dual;

17. 分区表

a. 分区表用途

  • 分区表通过对分区列的判断,把分区列不同的记录,放到不同的分区中。分区完全对应用透明。Oracle 的分区表可以包括多个分区,每个分区都是一个独立的段(SEGMENT),可以存放到不同的表空间中。查询时可以通过查询表来访问各个分区中的数据,也可以通过在查询时直接指定分区的方法来进行查询。
  • 分区表的优点:
    (1)由于将数据分散到各个分区中,减少了数据损坏的可能性;
    (2)可以对单独的分区进行备份和恢复;
    (3)可以将分区映射到不同的物理磁盘上,来分散 IO;
    (4)提高可管理性、可用性和性能。
  • 数据量大的表,一般大于 2GB;数据有明显的界限划分;对于 Long 和 Long Raw 类型列不能使用分区。

b. 分区表类型

  • 一般包括范围分区,散列分区,列表分区、复合分区(范围-散列分区,范围-列表分区)、间隔分区和系统分区等。

i. 范围分区

  • 范围分区根据数据库表中某一字段的值的范围来划分分区。
【语法】
在 Create Table 语句后增加
PARTITION BY RANGE(column_name)(PARTITION part1 VALUES LESS THAN (range1) [TABLESPACE tbs1],PARTITION part2 VALUES LESS THAN (range2) [TABLESPACE tbs2],...PARTITION partN VALUES LESS THAN (MAXVALUE) [TABLESPACE tbsN]
);【说明】
MAXVALUE:当分区列值都不在设置的范围内时,新增数据将到这个分区中【示例】
-- 创建表,并设置分区
create table myemp(empno number(4) primary key,ename varchar2(10),hiredate date,sal number(7,2),deptno number(2)
)
partition by range(sal) (partition p1 values less than(1000),partition p2 values less than(2000),partition p3 values less than(maxvalue)
);-- 插入数据
insert into myemp(empno,ename,hiredate,sal,deptno)
select empno,ename,hiredate,sal,deptno from emp;-- 查看工资1000-2000的数据
select * from myemp partition(p2);-- 删除工资小于1000的数据
delete from myemp partition(p1);-- 查看数据
select * from myemp;

ii. 列表分区

  • 列表分区明确指定了根据某字段的某个具体值进行分区,而不是像范围分区那样根据字段的值范围来划分的。
【语法】
在 Create Table 语句后增加
PARTITION BY LIST(column_name)(PARTITION part1 VALUES (values_list1),PARTITION part2 VALUES (values_list2),...PARTITION partN VALUES (DEFAULT)
);其中:column_name 是以其为基础创建列表分区的列。part1...partN 是分区的名称。values_list 是对应分区的分区键值的列表。DEFAULT 关键字允许存储前面的分区不能存储的记录。【示例】
-- 创建表,并设置分区
create table myemp2(empno number(4) primary key,ename varchar2(10),hiredate date,sal number(7,2),deptno number(2)
)
partition by list(deptno) (partition dept10 values(10),partition dept20 values(20),partition dept30 values(30),partition deptx values(default)
);-- 插入数据
insert into myemp2(empno,ename,hiredate,sal,deptno)
select empno,ename,hiredate,sal,deptno from emp;-- 查看部门20的数据
select * from myemp2 partition(dept20);-- 删除部门30的数据
delete from myemp2 partition(dept30);-- 查看数据
select * from myemp2;

18. PL/SQL

  • pl/sql:块结构语言,是 sql(Structured Query Language)语言的一种扩展,结合了 Oracle 过程语言(procedural language)进行使用。
  • pl/sql 块由三部分构成:声明部分、执行部分、异常部分。
  • PL/SQL 结构
[DECLARE]--声明变量等;
BEGIN--程序主要部分,一般用来执行过程语句或 SQL 语句;
[EXCEPTION]
--异常处理;
END;

a. 运算符

b. 变量与常量

  • 数据类型:

    • 常用标准类型:CHAR(CHARATER,NCHAR),VARCHAR2,NUMBER(P,S),DATE,BOOLEAN 等。
    • 属性类型:%TYPE 与 %ROWTYPE
      • %TYPE:可以用来定义数据变量的类型与已定义的数据变量(表中的列)一致。
      • %ROWTYPE:与某一数据库表的结构一致(修改数据库表结构,可以实时保持一致);
      • 访问方式声明为 rowtype 的 变量名.字段名。

i. 基本类型

  • 声明
【变量声明】
<变量名> 类型[:=初始值];
【示例】
name varchar2(20) := 'regino';【常量声明】
<变量名> CONSTANT 类型:=初始值;
【示例】
pi constant number(5,3):=3.14;
  • 运用
/*定义常量或变量、赋值使用示例*/
DECLAREp_empno constant number(4):=7369;p_ename varchar2(10);p_sal number(7,2);p_comm number(7,2);
BEGIN--赋值方式一:使用select into给变量赋值select ename,sal into p_ename,p_sal from emp where empno
=p_empno;--赋值方式二:使用赋值操作符“:=”给变量赋值p_comm:=500;--输出相关信息,DBMS_OUTPUT.PUT_LINE为具有输出功能的函数dbms_output.put_line('员工号:'|| p_empno||',姓名:'||
p_ename||',工资:'|| p_sal||',奖金:'|| p_comm);
END;【注意】
dbms_output 是 Oracle 提供的输出对象
put_line 是其一个方法,用于输出一个字符串
new_line 是其一个方法,用于输出新的一行(换行)

ii. %type 类型

  • 声明
【声明】
变量名称 表名.字段%type;
【示例:】
--表示变量 name 的类型和 emp.ename 的类型相同
name emp.ename%type;
  • 运用
/*定义常量或变量、赋值使用示例*/
DECLAREp_empno constant number(4):=7369;p_ename emp.ename%type;p_sal emp.sal%type;p_comm emp.comm%type;
BEGIN--赋值方式一:使用select into给变量赋值select ename,sal into p_ename,p_sal from emp where empno =
p_empno;--赋值方式二:使用赋值操作符“:=”给变量赋值p_comm:=500;--输出相关信息,DBMS_OUTPUT.PUT_LINE为具有输出功能的函数dbms_output.put_line('员工号:'|| p_empno||',姓名:'||
p_ename||',工资:'|| p_sal||',奖金:'|| p_comm);
END;

iii. %rowtype 类型

  • 声明
【声明】
变量名称 表%rowtype;
【示例:】
--表示变量 test 的类型为 emp 表的行类型;也有 .empno; .ename; .sal ;等属性
test emp%rowtype;
  • 运用
/*定义常量或变量、赋值使用示例*/
DECLAREp_empno constant number(4):=7369;emp_info emp%rowtype;p_comm emp.comm%type;
BEGIN--赋值方式一:使用select into给变量赋值select * into emp_info from emp where empno = p_empno;--赋值方式二:使用赋值操作符“:=”给变量赋值p_comm:=500;--输出相关信息,DBMS_OUTPUT.PUT_LINE为具有输出功能的函数dbms_output.put_line('员工号:'|| p_empno||',姓名:'||
emp_info.ename ||',工资:'|| emp_info.sal ||',奖金:'|| p_comm);
END;

c. 控制语句

i. 条件语句

【语法】
IF <条件 1> THEN语句
[ELSIF <条件 2> THEN语句]...
[ELSIF <条件 n> THEN语句]
[ELSE 语句]
END IF;【示例】
/*
根据员工的工资判断其工资等级(工资大于等于 5000 为 A 级,工资大于等于
4000 为 B 级,工资大于等于 3000 为 C 级,工资大于等于 2000 为 D 级,其它
为 E 级)
*/
DECLAREp_empno number(4):=7566;p_sal emp.sal%type;
BEGIN --用变量代替条件语句中的真值select sal into p_sal from emp where empno = p_empno;IF p_sal >= 5000 THENdbms_output.put_line('员工号为:' || p_empno || '的员工的工
资级别为:A级');ELSIF p_sal >= 4000 THENdbms_output.put_line('员工号为:' || p_empno || '的员工的工
资级别为:B级');ELSIF p_sal >= 3000 THENdbms_output.put_line('员工号为:' || p_empno || '的员工的工
资级别为:C级');ELSIF p_sal >= 2000 THENdbms_output.put_line('员工号为:' || p_empno || '的员工的工
资级别为:D级');ELSEdbms_output.put_line('员工号为:' || p_empno || '的员工的工
资级别为:E级');END IF;
END;

ii. 循环语句

  • LOOP
LOOP语句;EXIT WHEN <条件>
END LOOP;【示例】
/*
计算 1-10 的总和
*/
DECLAREp_sum number(4):=0;p_num number(2):=1;
BEGIN LOOPp_sum := p_sum + p_num;p_num := p_num + 1;EXIT WHEN p_num > 10;END LOOP;dbms_output.put_line('1-10的总和为:' || p_sum);
END;
  • WHILE LOOP
WHILE <条件>
LOOP语句;
END LOOP;【示例】
/*
计算 1-10 的总和
*/
DECLAREp_sum number(4):=0;p_num number(2):=1;
BEGIN WHILE p_num <= 10LOOPp_sum := p_sum + p_num;p_num := p_num + 1;END LOOP;dbms_output.put_line('1-10的总和为:' || p_sum);
END;
  • FOR
FOR <循环变量> IN [REVERSE] 下限..上限
LOOP语句;
END LOOP;【说明】..两点表示范围,1..4 表示时将从 1 到 4 进行循环,起始(例如 1)写前边,REVERSE 表示反转,循环时变成从 4 到 1 进行。【示例】
/*
计算 1-10 的总和
*/
DECLAREp_sum number(4):=0;p_num number(2):=1;
BEGIN FOR p_num IN 1..10LOOPp_sum := p_sum + p_num;END LOOP;dbms_output.put_line('1-10的总和为:' || p_sum);
END;

iii. 顺序语句

  • 指定顺序执行的语句;主要包括 null 语句。null 语句:是一个可执行语句,相当于一个占位符或不执行操作的空语句。主要用来提高程序语句的完整性和程序的可读性。
/*
输出 1-10 的数字但跳过数字 4
*/
DECLAREflag number(2):=0;
BEGIN WHILE flag < 10 LOOPflag := flag + 1;if flag = 4 thennull;-- 占位,不能去掉elsedbms_output.put_line(flag);end if;END LOOP;
END;

d. 异常处理

i. 异常语法

EXCEPTION WHEN <异常类型> THEN语句;WHEN OTHERS THEN语句;
  • 常配套使用的函数:

    • SQLCODE 函数:返回错误代码,
    • SQLERRM 函数:返回错误信息
  • 例如输出异常信息:DBMS_OUTPUT.PUT_LINE(‘其它异常,代码号:’||SQLCODE||’,
  • 异常描述:’||SQLERRM);

ii. 预定义异常

  • 预定义异常指 PL/SQL 程序违反 Oracle 规则或超越系统限制时隐式引发
    (由 Oracle 自动引发)。
  • 常见的预定义异常
    • CURSOR_ALREADY_OPEN 试图"OPEN"一个已经打开的游标
    • DUP_VAL_ON_INDEX 试图向有"UNIQUE"中插入重复的值
    • INVALID_CURSOR 试图对以关闭的游标进行操作
    • INVALID_NUMBER 在 SQL 语句中将字符转换成数字失败
    • LOGIN_DENIED 使用无效用户登陆
    • NO_DATA_FOUND 没有找到数据时
    • NOT_LOGIN_ON 没有登陆 Oracle 就发出命令时
    • PROGRAM_ERROR PL/SQL 存在诸如某个函数没有"RETURN"语句等内部问题
    • STORAGE_ERROR PL/SQL 耗尽内存或内存严重不足
    • TIMEOUT_ON_RESOURCE Oracle 等待资源期间发生超时
    • TOO_MANY_ROWS "SELECT INTO"返回多行时
    • VALUE_ERROR 当出现赋值错误
    • ZERO_DIVIDE 除数为零
【示例】
/*
预定义异常捕获并处理
*/
DECLAREp_result number(2);
BEGIN p_result := 1/0;dbms_output.put_line('没有异常!');EXCEPTIONWHEN ZERO_DIVIDE THENdbms_output.put_line('除数不能为0!代码为:'|| sqlcode ||',异常信息为:' || sqlerrm);WHEN OTHERS THENdbms_output.put_line('其它异常!代码为:'|| sqlcode || ',异常信息为:' || sqlerrm);
END;

iii. 自定义异常

  • 自定义异常:程序在运行过程中,根据业务等情况,认为非正常情况,可以自定义异常。对于这种异常,主要分三步来处理:

    1. 定义相关异常;在声明部分定义相关异常,
      格式:<自定义异常名称> EXCEPTION;
    2. 抛出异常;在出现异常部分抛出异常,
      格式:RAISE <异常名称>;
    3. 处理异常;在异常处理部分对异常进行处理,
      格式:when <自定义异常名称> then …,
  • 处理异常也可以使用 RAISE_APPLICATION_ERROR(ERROR_NUMBER,ERROR_MESSAGE) 存储过程进行处理,其中参数 ERROR_NUMBER 取值为 -20999~-20000 的负整数,参数 ERROR_MESSAGE 为异常文本消息。
【示例】
/*
判断 emp 中相应 empno 对应用户的奖金是否低于 500,如果低于则抛出并处理
自定义异常
*/
DECLAREp_comm emp.comm%type;--自定义异常,名称为comm_exceptioncomm_exception EXCEPTION;
BEGIN select nvl(comm,0) into p_comm from emp where empno=7499;if p_comm >= 500 thendbms_output.put_line('奖金大于等于500。');elseRAISE comm_exception;end if;EXCEPTIONWHEN comm_exception THENRAISE_APPLICATION_ERROR(-20001,'奖金低于500,太少了!');--dbms_output.put_line('奖金低于500!');WHEN OTHERS THENdbms_output.put_line('其它异常!代码为:'|| sqlcode || ',异常信息为:' || sqlerrm);
END;

19. 游标

a. 显式游标

  • 游标是映射在结果集中一行数据上的位置实体,使用游标,便可以访问结果集中的任意一行数据了,将游标放置到某行后,即可对该行数据进行操作;从上向下依次迭代结果集。

i. 游标语法

【定义语法】
CURSOR <游标名> IS <SELECT 语句> ;
【操作】OPEN <游标名> --打开游标FETCH <游标名> INTO 变量 1,变量 2,变量 3,....变量 n,;或者FETCH <游标名> INTO 行对象; --取出游标当前位置的值CLOSE <游标名> --关闭游标
【属性】%NOTFOUND --如果 FETCH 语句失败,则该属性为"TRUE",否则为"FALSE";%FOUND --如果 FETCH 语句成功,则该属性为"TRUE",否则为"FALSE";%ROWCOUNT --返回游标当前行的行数;%ISOPEN --如果游标是开的则返回"TRUE",否则为"FALSE";

ii. 游标使用

  • 使用游标显示员工表中所有的员工姓名、工作和工资
declarecursor cur_emp is select ename,job,sal from emp;p_ename emp.ename%type;p_job emp.job%type;p_sal emp.sal%type;
begin--打开游标open cur_emp;loop--取游标数据,从上往下移动一行fetch cur_emp into p_ename, p_job, p_sal;--如果下移后没有数据,则退出exit when cur_emp%notfound;--如果存在数据,则处理dbms_output.put_line('姓名为:' || p_ename || ',工作为:'|| p_job || ',工资为:' || p_sal);end loop;--关闭游标close cur_emp;
end;
  • 使用游标显示指定部门下的所有的员工姓名、工作和工资
代参数的游标
【定义】
CURSOR <游标名>(参数列表) IS <SELECT 语句>;【示例】
declarecursor cur_emp(dno emp.deptno%type) is select ename,job,sal from emp where deptno=dno;r_cur_emp cur_emp%rowtype;
begin--打开游标open cur_emp(20);loop--取游标数据,从上往下移动一行fetch cur_emp into r_cur_emp;--如果下移后没有数据,则退出exit when cur_emp%notfound;--如果存在数据,则处理dbms_output.put_line('姓名为:' || r_cur_emp.ename || ',工
作为:' || r_cur_emp.job || ',工资为:' || r_cur_emp.sal);end loop;--关闭游标close cur_emp;
end;--参考:使用 while 循环实现
declarecursor cur_dept_emps(dno emp.deptno%type) is select ename,job,sal  from emp where deptno=dno;emp_info cur_dept_emps%rowtype;
beginopen cur_dept_emps(20);fetch cur_dept_emps into emp_info;while cur_dept_emps%foundloopdbms_output.put_line('员工姓名为:'||emp_info.ename||',工作为:'||emp_info.job||',工资为:'||emp_info.sal);fetch cur_dept_emps into emp_info;end loop;close cur_dept_emps;
end;--参考:使用 for 循环实现
declarecursor cur_dept_emps(dno emp.deptno%type) is select ename,job,sal from emp where deptno=dno;emp_info cur_dept_emps%rowtype;
beginfor emp_info in cur_dept_emps(20)loopif cur_dept_emps%found thendbms_output.put_line('员工姓名为:'||emp_info.ename||',工作为:'||emp_info.job||',工资为:'||emp_info.sal);end if;end loop;
end;
  • 使用游标按员工的工种涨工资,总裁 800,经理 600,其他人员 300
declarecursor cur_emp is select empno,job from emp;p_empno emp.empno%type;p_job emp.job%type;
begin--打开游标open cur_emp;loop--取游标数据,从上往下移动一行fetch cur_emp into p_empno, p_job;--如果下移后没有数据,则退出exit when cur_emp%notfound;--如果存在数据,则处理if 'PRESIDENT'= p_job then update emp set sal = sal + 800 where empno = p_empno;elsif 'MANAGER' = p_job thenupdate emp set sal = sal + 600 where empno = p_empno;elseupdate emp set sal = sal + 300 where empno = p_empno;end if;end loop;--关闭游标close cur_emp;--提交修改commit;
end;

b. 隐式游标

  • 当执行一个 SQL 语句时,Oracle 会自动创建一个隐式游标,隐式游标主要处理 DML 语句,该游标的名称是 sql。隐试游标不能进行"OPEN",“CLOSE”,“FETCH” 这些操作。
  • 属性:
    • %NOTFOUND --如果 DML 语句没有影响到任何一行时,则该属性为"TRUE",否则为"FALSE";
    • %FOUND --如果 DML 语句影响到一行或一行以上时,则该属性为"TRUE",否则为"FALSE";
    • %ROWCOUNT --返回游标当最后一行的行数;
【示例】
/*
通过更新语句判断隐式游标的存在
*/
beginupdate emp set comm=comm + 300 where empno = 7369;if sql%notfound thendbms_output.put_line('empno对应的员工不存在');elsedbms_output.put_line('empno对应的员工数为:' ||sql%rowcount);end if;
end;

20. 存储过程与存储函数

a. 存储过程

  • 存储过程是命名的 pl/sql 程序块,封装数据业务操作,具有模块化、可重
    用、可维护、更安全特点;并且可以被程序调用。一般有 4 类型的存储过程,分别为不带参数、带输入参数、带输出参数、带输入输出参数。

i. 语法

【语法】CREATE [OR REPLACE] PROCEDURE <过程名>[(参数列表)] IS|AS[局部变量声明]BEGIN可执行语句[EXCEPTION异常处理语句]END [<过程名>];OR REPLACE:如果系统已存在该存储过程,将被替换
参数列表:参数不需要声明长度,可选
参数变量的类型:in 为默认类型,表示输入; out 表示只输出;in out 表示即
输入又输出;【调用方式】
在 PL/SQL 块中直接使用过程名;
在 PL/SQL 程序外使用 exec[ute] <过程名>[(参数列表)];

ii. 无参存储过程

-- 授予regino创建存储过程的权限
grant create procedure to regino;/*
使用无参存储过程,注意无参存储过程创建时不能使用()
*/
create or replace procedure pro_helloWorld
as
begindbms_output.put_line('Hello World.');
end;-- 方式一:调用存储过程,可加可不加()
beginpro_helloWorld;
end;-- 方式二:调用存储过程,可加可不加()
exec pro_helloWorld;

iii. 有输入参数存储过程

/*
使用有输入参存储过程
*/
create or replace procedure pro_add_emp(p_empno in emp.empno%type,p_ename in varchar2,p_sal number
)
as--将输入参数对应的数据插入emp表
begininsert into emp(empno, ename,sal) values(p_empno, p_ename, p_sal);
end; /-- 调用存储过程,向emp表插入新数据
beginpro_add_emp(2001,'regino2001',3000);pro_add_emp(2002,'regino2002',2000);pro_add_emp(2003,'regino2003',4000);
end;

iv. 有输出参数存储过程

/*
使用有输出参存储过程,计算 1 到 10 的总和并通过参数返回
*/
create or replace procedure pro_1to10_sum(p_sum out number
)
as
tem_sum number(4):=0;
beginfor i in 1..10looptem_sum := tem_sum + i;end loop;p_sum := tem_sum;
end; /-- 调用存储过程
declarep_sum number(4);
beginpro_1to10_sum(p_sum);dbms_output.put_line('1至10的和为:'|| p_sum);
end;

v. 有输入输出参数存储过程

/*
使用有输入、输出参存储过程;根据 empno 查询该员工号对应的员工的姓名和
工资
*/
create or replace procedure pro_query_enameAndSal_by_empno(s_empno emp.empno%type,s_ename out emp.ename%type,s_sal out emp.sal%type
)
as
beginselect ename,sal into s_ename, s_sal from emp where empno=s_empno;
end; /-- 调用存储过程
declarep_ename emp.ename%type;p_sal emp.sal%type;
begin--pro_query_enameAndSal_by_empno(7369, p_ename, p_sal);pro_query_enameAndSal_by_empno(7369, s_sal => p_sal, s_ename => p_ename);dbms_output.put_line('员工号为7369的员工名称为:'|| p_ename||',其
工资为:'|| p_sal);
end;

vi. 程序中调用存储过程

package cn.regino;import Java.sql.CallableStatement;
import Java.sql.Connection;
import Java.sql.DriverManager;
import Java.sql.SQLException;
import Oracle.jdbc.OracleTypes;public class TestProcedure {public static void main(String[] args) {Connection conn = null;CallableStatement call = null;try {Class.forName("Oracle.jdbc.OracleDriver");String url = "jdbc:Oracle:thin:@localhost:1521:orcl";conn = DriverManager.getConnection(url, "regino", "regino");call = conn.prepareCall("{call pro_query_enameAndSal_by_empno(?,?,?)}");//设置输入型参数call.setInt(1, 7369);//注册输出型参数call.registerOutParameter(2, OracleTypes.VARCHAR);call.registerOutParameter(3, OracleTypes.NUMBER);//调用存储过程call.execute();//获取返回值String ename = call.getString(2);//员工名称double sal = call.getDouble(3);//员工工资System.out.println("员工号为7369的员工名称为:" + ename + ",工资为:" + sal);} catch (Exception e) {e.printStackTrace();} finally {try {if(call != null){call.close();}if(conn != null){conn.close();}} catch (SQLException e) {e.printStackTrace();} } }
}

vii. 删除存储过程

【语法】
DROP PROCEDURE <过程名>;【示例】
drop procedure pro_1to10_sum;

b. 存储函数

  • 存储函数与过程不同的是,存储函数有 return 语句;一般情况下如果在需要一个返回值时可使用存储函数。

i. 语法

CREATE [OR REPLACE] FUNCTION <函数名>[(参数列表)] RETURN 数据类型
IS|AS[局部变量声明]BEGIN可执行语句[EXCEPTION 异常处理语句]RETURN 返回值;END [<函数名>];变量的类型:in 为默认类型,表示输入; out 表示只输出;in out 表示即输入
又输出;【使用方式】
直接在 select 中使用和其它系统函数使用方式一样; 在 PL/SQL 块中调用使用;

ii. 无参存储函数

/*
使用无参存储函数;注意创建时函数名称不能使用()
但是在调用时候可加可不加()
*/
create or replace function fun_helloWorld
return varchar2as
beginreturn 'Hello World';
end; -- 方式1:调用存储函数
select fun_helloWorld() from dual;-- 方式2:调用存储函数
declarestr varchar2(20);
beginstr :=fun_helloWorld;dbms_output.put_line(str);
end;

iii. 有输入参数存储函数

/*
使用存储函数:根据员工号,查询并返回该员工的年薪
*/
create or replace function fun_get_annualSal_by_empno(p_empno  emp.empno%type)
return number asp_sal emp.sal%type;p_comm emp.comm%type;
beginselect sal,comm into p_sal, p_comm from emp where empno=p_empno;return 12*p_sal + nvl(p_comm,0);
end; -- 调用存储函数
select fun_get_annualSal_by_empno(7369) from dual;

iv. 有输入输出参数存储函数

/*
使用具有输入输出参数的存储函数:根据员工号,查询并返回该员工的年薪,姓名,奖金
*/
create or replace function fun_get_annualSal_by_empno2(p_empno emp.empno%type,p_ename out emp.ename%type,p_comm out emp.comm%type
)
return number asp_sal emp.sal%type;
beginselect ename,sal,nvl(comm,0) into p_ename,p_sal, p_comm from emp where empno=p_empno;return 12*p_sal + p_comm;
end; /-- 调用存储函数
declarep_annualSal number(10,2);p_ename emp.ename%type;p_comm emp.comm%type;
beginp_annualSal := fun_get_annualSal_by_empno2(7499,p_ename,p_comm);dbms_output.put_line('员工姓名为:'||p_ename||',奖金为:'||p_comm||',年薪为:'||p_annualSal);
end;

v. 程序中调用存储函数

package cn.regino;import Java.sql.CallableStatement;
import Java.sql.Connection;
import Java.sql.DriverManager;
import Java.sql.SQLException;
import Oracle.jdbc.OracleTypes;public class TestFunction {public static void main(String[] args) {Connection conn = null;CallableStatement call = null;try {Class.forName("Oracle.jdbc.OracleDriver");String url = "jdbc:Oracle:thin:@localhost:1521:orcl";conn = DriverManager.getConnection(url, "regino", "regino");call = conn.prepareCall("{? = call  fun_get_annualSal_by_empno2(?,?,?)}");//注册存储函数返回值call.registerOutParameter(1, OracleTypes.DOUBLE);//设置输入参数,员工号call.setInt(2, 7499);//注册输出参数,员工姓名call.registerOutParameter(3, OracleTypes.VARCHAR);//注册输出参数,奖金call.registerOutParameter(4, OracleTypes.DOUBLE);call.execute();System.out.println("员工姓名为:" + call.getString(3) + ",奖金为:" + call.getDouble(4) + ",年薪为:" + call.getDouble(1));} catch (Exception e) {e.printStackTrace();} finally {try {if(call != null){call.close();}if(conn != null){conn.close();}} catch (SQLException e) {e.printStackTrace();}}}
}

vi. 删除存储函数

【语法】
DROP FUNCTION <函数名>;【示例】
drop function fun_helloWorld;
drop function fun_get_annualSal_by_empno;
drop function fun_get_annualSal_by_empno2;

c. 存储过程与存储函数的区别

  • 返回值的区别,函数一定要有 1 个返回值或有多个通过输出参数的返回值,而存储过程是通过输出参数返回的,可以有多个或者没有;
  • 调用的区别,函数可以在 sql 语句中直接调用,而存储过程必须单独调用;
  • 函数一般情况下是用来计算并返回一个计算结果,而存储过程一般是用来完成特定的数据操作(比如修改、插入数据库表或执行某些 DDL 语句等等)

21. 程序包

a. 简介

  • 包(Package)是一组相关过程、函数、变量、常量、类型和游标等 PL/SQL 程序设计元素的组合。包具有面向对象设计的特点,是对这些 PL/SQL 程序设计元素的封装。包包括两部分:定义一个包(包头)、实现一个包(包体);只有当定义包后才能实现包体.其中包体中的函数名与过程名须和包头中定义的函数、过程一样。
  1. 包和包体必须有相同的名字;
  2. 包的开始没有 begin 语句,与存储过程和函数不同;
  3. 在包头部分定义函数和过程的名称和参数,具体实现在包体中定义;
  4. 在包体内声明常量、变量、类型定义、异常、及游标时不使用 declare;
  5. 包体内的过程和函数的定义不要 create or replace 语句;
  6. 包定义和包体两者分离。

b. 创建包

i. 定义包(包头)

CREATE [OR REPLACE] PACKAGE <包名> AS|IS --公共类型和对象声明--子程序说明
END;【注意】包的定义中不需要 begin 关键字;函数和过程的定义也不需要 create
or replace。另外,包中定义的变量、常量在包体中可直接使用。【示例语法】
create or replace package <Package_name> as-- 定义自定义类型type <TypeName> is <Datatype>;-- 公共常量定义<ConstantName> constant <Datatype> := <Value>;--声明常量-- 公共变量定义<VariableName> <Datatype>; --数据类型-- 公共函数或存储过程定义function <FunctionName>(<Parameter> <Datatype>) return <Datatype>; --函数procedure <ProcedurenName>(<Parameter> <Datatype>); --存储过程 end [Package_name];

ii. 实现包(包体)

CREATE [OR REPLACE] PACKAGE BODY <包名> AS --公共类型和对象声明[BEGIN]-初始化语句
END;【示例语法】
create or replace package body <Package_name> as-- 私有自定义类型(包内可用)type <TypeName> is <Datatype>;-- 私有常量(包内可用)<ConstantName> constant <Datatype> := <Value>-- 私有变量(包内可用)<VariableName> <Datatype>;-- 函数或存储过程的实现function <FunctionName>(<Parameter> <Datatype>) return <Datatype> as --函数实现<LocalVariable> <Datatype>;begin<Statement>;return(<Result>);end;procedure <ProcedureName>(<Parameter> <Datatype>) as --存储过程实
现<LocalVariable> <Datatype>;begin<Statement>;end;begin--初始化包体<Statement>;end [Package_name];

iii. 应用

/*
创建一个包含有变量、存储过程和函数的包;其中
存储过程可根据员工号查询并输出员工的姓名和工资
函数中利用定义的变量,然后则根据员工号查询出该员工奖金并返回
*/
--定义包
create or replace package pack_1 as--定义存储过程
procedure pro_1(p_empno emp.empno%type);--定义函数
function fun_1(p_empno emp.empno%type) return number;
end;-- 【切记】需要先定义并编译(执行)包,之后再实现并编译(执行)包体
--实现包(包体)
create or replace package body pack_1 as--定义包变量
p_comm number(7,2);
procedure pro_1(p_empno emp.empno%type) asp_ename emp.ename%type;p_sal emp.sal%type;beginselect ename,sal into p_ename,p_sal from emp where empno=p_empno;dbms_output.put_line('员工号为:'||p_empno||',对应的员工姓名为:'|| p_ename||',工资为:'||p_sal);end;function fun_1(p_empno emp.empno%type) return number as f_comm emp.comm%type;beginselect nvl(comm,0) into p_comm from emp where empno=p_empno;return p_comm;end;
end;--打开输出
set serveroutput on;begin--调用包中的存储过程pack_1.pro_1(7499);--调用包中的函数dbms_output.put_line('7499对应的奖金为:'||pack_1.fun_1(7499));
end;

iv. 程序中调用包

  1. 创建包
/*
利用包编写一个带有游标类型输出参数的存储过程
根据部门编号查询该部门下的员工
*/
create or replace package pack_2 as--自定义一个游标类型type empCursor is ref cursor;procedure pro_1(p_deptno in emp.deptno%type, p_empCursor out empCursor);
end;create or replace package body pack_2 asprocedure pro_1(p_deptno in emp.deptno%type, p_empCursor out
empCursor) asbeginopen p_empCursor for select * from emp where deptno=p_deptno;end;
end;
  1. 程序中调用上述包
package cn.regino;import Java.sql.CallableStatement;
import Java.sql.Connection;
import Java.sql.DriverManager;
import Java.sql.ResultSet;
import Java.sql.SQLException;
import Oracle.jdbc.OracleCallableStatement;
import Oracle.jdbc.OracleTypes;public class TestPackage {public static void main(String[] args) {Connection conn = null;CallableStatement call = null;try {Class.forName("Oracle.jdbc.OracleDriver");String url = "jdbc:Oracle:thin:@localhost:1521:orcl";conn = DriverManager.getConnection(url, "regino", "regino");call = conn.prepareCall("{call pack_2.pro_1(?,?)}");//设置输入型参数call.setInt(1, 10);//注册输出型参数(类型为游标)call.registerOutParameter(2, OracleTypes.CURSOR);call.execute();ResultSet rs = ((OracleCallableStatement)call).getCursor(2);if(rs != null){while(rs.next()){System.out.println("员工号为:" + rs.getInt(1) + ",姓名为:" + rs.getString(2));}rs.close();}} catch (Exception e) {e.printStackTrace();} finally {try {if(call != null){call.close();}if(conn != null){conn.close();}} catch (SQLException e) {e.printStackTrace();} } }
}

c. 删除包

【语法】
DROP PACKAGE <包名>;【示例】
drop package pack_1;

22. 触发器

a. 语法

【语法】CREATE [OR REPLACE] TRIGGER <触发器名>BEFORE|AFTERINSERT|DELETE|UPDATE [OF <列名>] ON <表名>[FOR EACH ROW]<pl/sql 块>【说明】关键字"BEFORE"在操作完成前触发;"AFTER"则是在操作完成后触发;关键字"FOR EACH ROW"指定触发器每行触发一次,若不指定则为表级触发器.关键字"OF <列名>" 不写表示对整个表的所有列.pl/sql 块中不能使用 commit;【特殊变量】:new --为一个引用最新的行值;:old --为一个引用以前的行值;
这些变量只有在使用了关键字 "FOR EACH ROW"时才存在.且 update 语句两个
都有,而 insert 只有:new ,delect 只有:old;

b. 行级触发器

  • 【示例 1】涨工资
/*
触发器使用:给员工涨工资(涨后工资应该大于涨前)后,在后台输出更新
前和更新后的工资
*/
create or replace trigger tri_emp_upd_salafterupdate of sal on empfor each row
beginif :old.sal < :new.sal thendbms_output.put_line('更新前工资为:'||:old.sal||',更新后工资为:'||:new.sal);elseraise_application_error(-20002,'工资不能越涨越低!');end if;
end; -- 更新工资值,并触发行级触发器
update emp set sal = 8888 where empno = 1002;
  • 【示例 2】触发器+序列实现主键自增长
/*
触发器使用:给emp表的empno添加触发器,在插入记录时自动填入值
*/
-- 1、创建序列
create sequence seq_emp_empno;
-- 2、创建触发器
create or replace trigger tri_emp_ins_empnobeforeinsert on empfor each row
begin-- 给将要插入表的记录:new 中的empno设置sequence中的值select seq_emp_empno.nextval into :new.empno from dual;
end;-- 新增员工数据,测试触发器+序列的组合使用
insert into emp(ename,sal) values('regino002',2000);
commit;

c. 表级触发器

/*
触发器使用:删除表的同时备份表数据到另一张备份表
*/
-- 1、从emp表结果中创建一张表并复制数据
create table emp2 as select * from emp;-- 2、创建备份表emp_bak
create table emp_bak as select * from emp2 where 1=2;-- 3、创建表触发器,当对表操作时触发
create or replace trigger tri_emp2_delbeforedelete on emp2
begin-- 将emp2表中的数据备份到emp_bakinsert into emp_bak select * from emp2;
end; -- 4、测试删除emp2表的数据
delete from emp2;
select * from emp2;
select * from emp_bak;

d. 开启禁用触发器

【禁用某个触发器】
ALTER TRIGGER <触发器名> DISABLE
【示例】
alter trigger tri_emp_upd_sal disable;
update emp set sal = 8888 where empno = 1002;【重新启用触发器】
ALTER TRIGGER <触发器名> ENABLE
【示例】
alter trigger tri_emp_upd_sal enable;
update emp set sal = 8888 where empno = 1002;【禁用表的所有触发器】
ALTER TABLE <表名> DISABLE ALL TRIGGERS;
【示例】
alter table emp disable all triggers;【启用表的所有触发器】
ALTER TABLE <表名> ENABLE ALL TRIGGERS;
【示例】
alter table emp enable all triggers;【删除触发器】
DROP TRIGGER <触发器名>;
【示例】
drop trigger tri_emp_upd_sal;

23. 数据字典

  • 数据字典对用户来说是一组只读的表;数据字典内容包括,数据库中所有模式对象的信息。Oracle 数据字典中,对象名称多数以"USER.",“ALL.”,“DBA.”。前缀"USER."视图中记录通常记录执行查询的帐户所拥有的对象的信息,"ALL."视图中记录包括"USER"记录和授权至 PUBLIC 或用户的对象的信息,"DBA."视图包含所有数据库对象,而不管其所有者。





24. 角色

  • Oracle 提供了三种标准的角色(role):CONNECT、RESOURCE 和 DBA。

    1. CONNECT Role(连接角色)
      临时用户,特别是那些不需要建表的用户,通常只赋予他们 CONNECT role。CONNECT 是使用 Oracle 的简单权限,这种权限只有在对其他用户的表有访问权时,包括 select、insert、update 和 delete 等,才会变得有意义。
    2. RESOURCE Role(资源角色)
      更可靠和正式的数据库用户可以授予 RESOURCE role。RESOURCE 提供给用户另外的权限以创建他们自己的表、序列、过程、触发器、索引和簇。
    3. DBA Role(数据库管理员角色)
      DBA role 拥有所有的系统权限–包括无限制的空间限额和给其他用户授予
      各种权限的能力。
  • 除此以上角色外;还可以自行创建角色。用户创建的 role 可以由表或系统权限或两者的组合构成。为了创建 role,用户必须具有 CREATE ROLE 系统权限。

a. 创建角色

  • 创建角色后,可以对角色授予权限;授权的语法和前面授权给用户的语法相同。
【语法】
CREATE ROLE <role_name>;【示例】
-- system 用户登录,授予regino 创建角色的权限
grant create role to regino;-- 创建角色
create role role_regino;-- 授予emp的select 操作权限给role_regino角色
grant select on emp to role_regino;-- 给scott用户授予role_regino的角色
grant role_regino to scott;

b. 删除角色

【语法】
DROP ROLE <role_name>;【示例】
drop role role_regino;

25. 闪回

a. 闪回简介

  • 在 Oracle 的操作工程中,会不可避免地出现操作失误或者用户失误,例如不小心删除了一个表等,这些失误和错误可能会造成重要数据的丢失,最终导致 Oracle 数据库停止。
  • 在传统操作上,当发生数据丢失、数据错误问题时,解决的主要办法是数据的导入导出、备份恢复技术,这些方法都需要在发生错误前,有一个正确的备份才能进行恢复。为了减少这方面的损失,Oracle 提供了闪回技术。有了闪回技术,就可以实现数据的快速恢复,而且不需要数据备份
  • 闪回特点
    • 传统的恢复技术缓慢:它是整个数据库或者一个文件恢复,不只恢复损坏的数据在数据库日志中每个修改都必须被检查;
    • 闪回速度快:通过行和事务把改变编入索引,仅仅改变了的数据会被恢复;
    • 闪回命令容易,没有复杂步骤。

b. 闪回类型

  • 主要有三种闪回:闪回表(flashback table)、闪回删除(flashback drop)、闪回数据库(flashback database);一般情况下对数据库的闪回需要配置闪回数据库,然后自动产生闪回日志;再根据闪回日志恢复数据库。

c. 闪回查询

  • 根据闪回日志可以快速查询在某个时间点的数据。
--查看 10 秒之前的 emp 表
select * from emp as of timestamp sysdate - interval '10' second;
select * from emp as of scn timestamp_to_scn(sysdate - interval '10'
second);
【说明】
as of timestamp 是固定写法,查询某个时间点对应的数据
as of scn 查询某 scn 对应的数据
sysdate – interval ‘10’second 是时间值的计算--通过查询某个时间的数据来更新现有数据
--将 7499 员工的姓名更新为 5 分钟之前的姓名
update emp e set ename =
(select ename from emp
as of timestamp systimestamp - interval '5' minute where
empno=e.empno)
where empno=7499;

d. 闪回表

  • 闪回表(flashback table)实际上是将表中的数据快速恢复到过去的一个焦点或者系统改变号 SCN 上;对进行表闪回的表必须 row movement 为 enable。

    • SCN: System Change Number.
    • 实现表的闪回,需要使用到与撤销表空间相关的 undo 信息,通过 show parameter undo 命令可以了解这些信息。
    • conn sys/orcl as sysdba
    • show parameters undo; // undo 表空间
    • alter system set undo_retention=1200 scope=both;
  • undo_retention:数据保留时间长度(默认是 900 秒)
  • scope 参数的值:
  • momory-当前 session 中有效
  • spfile: 修改配置文件,但当前会话中无效
  • both:当前会话有效,同时修改配置文件
  • undo 表空间:保存了所有的操作记录(2G 的空间)因为有了该表空间才可以进行闪回
【语法】
flashback table [schema.]table_name[,...n] to {[scn] | [timestamp] [[enable | disable] triggers]};【说明】
scn:表示通过系统改变号进行闪回;scn 系统改变号一般和系统时间相对应;查看当前系统时间和所对应系统 scn:
select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),
timestamp_to_scn(sysdate) from dual;timestamp:表示通过时间戳的形式来进行闪回;
enable|disable triggers:表示触发器恢复之后的状态,默认为 disable。rowid 这个伪列是 Oracle 默认提供给每一个表的,主要用于记录每一行数据存储的磁盘物理地址。当删除一行记录后,后面的记录依次跟进上来,当需要恢复某一个中间的行时,就需要行具备行移动功能(alter table <表名>
enable row movement;)【示例】
-- 授权用户闪回表的权限
grant flashback any table to regino;-- 查看当前时间点或scn号
select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),
timestamp_to_scn(sysdate) from dual;-- 删除数据
delete from emp where empno = 7449;
commit;--允许行移动
alter table emp enable row movement;-- 方式一;使用时间点闪回表
flashback table emp to timestamp to_timestamp('时间格式字符串','yyyy-mm-dd HH24:mi:ss');-- 方式二;使用SCN闪回表
flashback table emp to scn SCN号;

e. 闪回删除

  • 闪回删除(flashback drop)。当整个表被删除并在回收站查询到的话;可以对表进行闪回。show recyclebin:可以显示当前用户 recyclebin 中的表。系统参数 recyclebin 控制表删除后是否到回收站,show parameter recyclebin 可以查看该参数的状态。对于系统参数的修改有两种,全局的修改和会话的修改:
    (1)alter system set param_name=param_value;
    (2)alter session set param_name=param_value;
  • show recyclebin; --查看回收站
  • purge recyclebin; --清空回收站
【语法】
flashback table table_name to before drop [rename to new_name]; 【说明】
rename to new_name:如果在删除原表之后又重新创建了一个一样名称的表,那么恢复回收站的表时可以对表名进行重命名【示例】
-- 删除表
drop table emp;-- 恢复表
flashback table emp to before drop;

26. 数据备份与恢复

a. 数据备份

--全表备份
exp regino/regino@orcl file=d:\database\Oracle_data\regino.dmp
full=y--指定表备份
exp regino/regino@orcl
file=d:\database\Oracle_data\regino_emp_dept.dmp tables=(emp,dept)【说明】full:完整导出数据库非空数据表,一般使用 system 具有管理员权限的用户在命令行下进行操作。

b. 数据恢复

--全表恢复
imp regino/regino@orcl ignore=y
file=d:\database\Oracle_data\regino.dmp full=y--指定表恢复
imp regino/regino@orcl ignore=y
file=d:\database\Oracle_data\regino_emp_dept.dmp tables=(emp,dept)【说明】ignore:忽略创建错误

27. 性能优化

  1. 查两张以上表时,把记录少的放在右边
  2. WHERE 子句中的连接顺序
    • Oracle 采用自上而下的顺序解析 WHERE 子句,根据这个原则,那些可以过滤掉最大数量记录的条件应写在 WHERE 子句最后。
    • 例如:查询员工的编号,姓名,工资,部门名
      如果 emp.sal>1500 能过滤掉半数记录的话,
      select emp.empno,emp.ename,emp.sal,dept.dname
      from emp,dept
      where (emp.deptno = dept.deptno) and (emp.sal > 1500)
  3. SELECT 子句中避免使用*号
    • Oracle 在解析的过程中,会将*依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间
  4. 避免对大表进行无条件或无索引的的扫描
  5. 清空表时用 TRUNCATE 替代 DELETE
  6. 尽量多使用 COMMIT;因为 COMMIT 会释放回滚点
  7. 用索引提高查询效率,善用索引
    • 避免在索引列上使用 NOT;因为 Oracle 服务器遇到 NOT 后,他就会停止目前的工作,转而执行全表扫描。
    • 避免在索引列上使用计算;WHERE 子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描,这样会变得慢
      • 例如,SAL 列上有索引,

        • 低效:
          SELECT EMPNO,ENAME
          FROM EMP
          WHERE SAL*12 > 24000;
        • 高效:
          SELECT EMPNO,ENAME
          FROM EMP
          WHERE SAL > 24000/12;
  8. 字符串型,能用=号,不用 like
    • =号表示精确比较,like 表示模糊比较
  9. 用 >= 替代 >
    • 低效:
      SELECT * FROM EMP WHERE DEPTNO > 3
      首先定位到 DEPTNO=3 的记录并且扫描到第一个 DEPT 大于 3 的记录
    • 高效:
      SELECT * FROM EMP WHERE DEPTNO >= 4
      直接跳到第一个 DEPT 等于 4 的记录
  10. 用 IN 替代 OR
    • select * from emp where sal = 1500 or sal = 3000 or sal = 800;
    • select * from emp where sal in (1500,3000,800);
  11. 用 exists 代替 in;not exists 代替 not in
    • not in 字句将执行一个内部的排序和合并,任何情况下,not in 是最低效的,子查询中全表扫描;表连接比 exists 更高效
  12. 用 UNION-ALL 替换 UNION
    • 当 SQL 语句需要 UNION 两个查询结果集合时,这两个结果集合会以 UNION-ALL 的方式被合并, 然后在输出最终结果前进行排序. 如果用 UNION ALL 替代 UNION, 这样排序就不是必要了. 效率会因此得到提高。
  13. 避免使用耗费资源的操作
    • 带有 DISTINCT,UNION,MINUS,INTERSECT 的 SQL 语句会启动 SQL 引擎 执行耗费资源的排序(SORT)功能. DISTINCT 需要一次排序操作, 而其他的至少需要执行两次排序. 通常, 带有 UNION, MINUS , INTERSECT 的 SQL 语句都可以用其他方式重写。
  • 最后;同样的操作有些时候可以在程序上处理的就程序上处理,毕竟在内存中的执行速度比在硬盘上执行要高非常多。

28. 项目切换到 Oracle 数据库

  1. 修改 applicationContext.xml 中的数据库方言
  2. 修改 db.properties 中的数据库驱动类和用户名密码
  3. 其它修改(如创建 user 表时将表名修改为 t_user,user 是 Oracle 数据库的关键字)

原文链接:https://qwert.blog.csdn.net/article/details/105830866

Oracle 数据库的概念与使用相关推荐

  1. Oracle数据库碎片分析,oracle数据库碎片概念与分析

    什么是oracle的碎片呢,百度一大片关于oracle碎片的概念,以前看了一两遍,以为看了就了解了碎片了,其实不然,在百度上看的内容如下 ------------------------------- ...

  2. mysql中的scn,oracle数据库SCN概念

    目录 1.SCN的介绍 2.SCN的工作机制 3.SCN的增加 4.其他的SCN 5测试 6小结 7问题 1.SCN的介绍 Oracle中的SCN有下面几种: 1)系统检查点scn(v$databas ...

  3. Oracle数据库基本概念理解(3)

    /* =========================================================== | PL/SQL编程 ========================== ...

  4. Oracle数据库基本概念理解(2)

    --删除用户 drop user sz cascade; --创建表空间 create tablespace worktablsp datafile 'C:\app\lenovo\oradata\or ...

  5. Oracle数据库基本概念理解(1)

    --函数 数字转换为字符 --0 强制位数,9位数不够不显示 $美元 SELECT TO_CHAR(124.3456,'0000.00') FROM dual ; SELECT TO_CHAR(124 ...

  6. Oracle数据库的基本使用和高级查询

    1.Oracle体系结构 本次使用的是Oracle18c数据库版本 java学习交流Q群:1004577069 1>数据库Oracle数据库时数据的物理存储,这就包括(数据库文件ORA或者DBF ...

  7. oracle数据库_实例_用户_表空间之间的关系

    oracle数据库_实例_用户_表空间之间的关系 基础概念:Oracle数据库.实例.用户.表空间.表之间的关系 数据库: Oracle数据库是数据的物理存储.这就包括(数据文件ORA或者DBF.控制 ...

  8. Oracle数据库深入学习

    一.Oracle概念 oracle数据可系统是美国oracle(甲骨文)公司提供的以分布式数据库为核心的一组软件产品,是目前最流行的客户/服务器或B/S体系结构的数据库之一,oracle数据库时目前世 ...

  9. Oracle数据库--从入门到装逼

    目录 1 Oracle基础 1.1 Oracle简介 1.1.1 什么是Oracle 1.1.2 Oracle体系结构 1.2 Oracle安装与配置 1.2.1 安装前准备 1.2.2 安装步骤 1 ...

最新文章

  1. [YTU]_2625( 构造函数和析构函数)
  2. 计算机原理的进位输入是什么,进位控制实验计算机组成原理实验报告
  3. 欢迎使用CSDN-markdown编辑器!!!
  4. 二叉查找树-优化版,使用了指针引用
  5. Authorization object where used list in tcode SUIM
  6. hibernate实现多变联合查询
  7. 计算机网络数据链路层 --- 选择重传协议(SR)
  8. 海森堡不确定性原理实验
  9. 「02」《机器学习经·天工开物篇》
  10. PhotoshopCS2相关教程网址
  11. 拓端tecdat荣获腾讯云+社区年度最佳作者奖
  12. 商城系统演示站 -多用户商城系统
  13. 亲测沉梦Free免费易支付系统源码支持码支付
  14. 三极管电路限流电阻如何选择
  15. 跨平台显示MMD模型
  16. 【GANs学习笔记】(十六)CGAN、TRIPLEGAN
  17. 直击文印痛点 中小企业需要这样一台复合机
  18. 最小编辑距离 动态规划 python
  19. [免费的win7 娘]WES7SP1 测试心得
  20. linePlusBarChart(python -nvd3)

热门文章

  1. 千锋教育Web前端——PC端企业类型整页制作
  2. 从10年全网第1,看海尔智家披荆斩棘换来的持续性
  3. 洛可可孟宪志:商业、设计和美学并不冲突 独乐乐不如众乐乐
  4. cadence SPB17.4 - allegro 元件一次性旋转任意角度
  5. 2021年预训练语言模型及微调的最新进展
  6. [漏洞预警]交易所漏洞之薅羊毛分析
  7. 机器阅读理解技术初探Bi-DAF
  8. 大学生数学竞赛教程【蒲和平】
  9. “变态”的JavaScript 发明人--布兰登·艾奇
  10. 益聚星荣:回忆杀来袭,QQ秀上演乌龙下架 网友们落下了“时代的眼泪”