Oracle 数据库实用教程
目录
-
第一部分:基础入门
(图片来源网络,侵删)- 1 什么是 Oracle 数据库?
- 2 为什么选择 Oracle?
- 3 安装与配置
- 4 连接到 Oracle 数据库
- 5 基本 SQL 语句
-
第二部分:核心概念与对象
- 1 体系结构:实例、数据库、表空间
- 2 数据类型
- 3 表 的创建与管理
- 4 约束
- 5 索引
- 6 视图
- 7 序列 与同义词
-
第三部分:数据操作与查询
- 1 DML (Data Manipulation Language) 详解
- 2 单表查询
- 3 多表连接查询
- 4 分组与聚合
- 5 子查询
- 6 合并数据
-
第四部分:PL/SQL 编程
- 1 什么是 PL/SQL?
- 2 基本结构:声明、执行、异常
- 3 变量与常量
- 4 控制结构
- 5 游标
- 6 存储过程 与函数
-
第五部分:数据库管理与维护
(图片来源网络,侵删)- 1 用户与权限管理
- 2 表空间管理
- 3 备份与恢复概述
- 4 数据导入导出
-
第六部分:进阶主题
- 1 事务控制
- 2 性能优化基础
- 3 Oracle 12c/19c/21c 新特性简介
-
第七部分:学习资源与总结
第一部分:基础入门
1 什么是 Oracle 数据库?
Oracle 数据库是由 Oracle 公司开发的一款关系型数据库管理系统,它使用结构化查询语言 作为其数据子集语言,它是一个功能强大、稳定可靠、适用于企业级应用(如银行、电信、大型电商)的数据库产品。
2 为什么选择 Oracle?
- 高性能和高可用性:支持大规模并发访问和复杂的查询。
- 稳定性与安全性:经过市场长期检验,拥有完善的安全机制和故障恢复能力。
- 可扩展性:可以从单机扩展到庞大的集群和云平台。
- 完整的产品生态:提供了从数据库、中间件到应用开发的一整套解决方案。
3 安装与配置
对于初学者,最简单的安装方式是使用 Oracle 提供的 Oracle Database Express Edition (XE),这是一个免费、轻量版的 Oracle 数据库,非常适合学习和开发。

- 下载:访问 Oracle 官网,搜索 "Oracle Database XE" 并下载对应操作系统的版本。
- 安装:按照安装向导一步步操作,安装过程中会提示你设置一个 SYS 和 SYSTEM 用户的密码,请务必记住。
- 验证:安装完成后,可以在开始菜单找到 "SQL*Plus" 或 "SQL Developer" 来连接数据库。
4 连接到 Oracle 数据库
有两种主要方式连接:
*使用 SQLPlus (命令行工具)**
SQL*Plus 是 Oracle 自带的命令行客户端。
- 在开始菜单中找到并打开 "SQL*Plus"。
- 在提示符下输入用户名和密码。
# 用户名通常是 SYSTEM,密码是你安装时设置的 SQL> SYSTEM Enter password: ******** Connected.
使用 SQL Developer (图形化工具)
SQL Developer 是一个免费的图形化 IDE,更直观易用。
- 下载并安装 SQL Developer。
- 启动后,点击左上角的 "+" 号新建连接。
- 填写连接信息:
- Connection Name: 自定义,如 "My Local Oracle"
- Username:
SYSTEM - Password: 你设置的密码
- Connection Type:
Basic - Hostname:
localhost - Port:
1521(XE 版本的默认端口) - SID:
XE(XE 版本的默认服务标识符)
- 点击 "Test" 测试连接,成功后点击 "Connect"。
5 基本SQL语句
SQL (Structured Query Language) 是与数据库交互的标准语言,主要分为四类:
- DDL (Data Definition Language):定义数据库对象。
CREATE,ALTER,DROP,TRUNCATE
- DML (Data Manipulation Language):操作数据。
INSERT,UPDATE,DELETE
- DQL (Data Query Language):查询数据。
SELECT
- DCL (Data Control Language):控制权限。
GRANT,REVOKE
示例:创建一个表并插入数据
-- 1. 创建一张员工表
CREATE TABLE employees (
employee_id NUMBER(6) PRIMARY KEY,
first_name VARCHAR2(20),
last_name VARCHAR2(25),
email VARCHAR2(25),
hire_date DATE,
salary NUMBER(8, 2)
);
-- 2. 向表中插入数据
INSERT INTO employees (employee_id, first_name, last_name, email, hire_date, salary)
VALUES (101, 'John', 'Doe', 'john.doe@example.com', TO_DATE('2025-01-15', 'YYYY-MM-DD'), 5000.00);
INSERT INTO employees (employee_id, first_name, last_name, email, hire_date, salary)
VALUES (102, 'Jane', 'Smith', 'jane.smith@example.com', TO_DATE('2025-02-20', 'YYYY-MM-DD'), 6000.00);
-- 3. 提交事务,使数据永久保存
COMMIT;
-- 4. 查询数据
SELECT * FROM employees;
第二部分:核心概念与对象
1 体系结构:实例、数据库、表空间
理解这三个概念是管理 Oracle 的基础。
- 数据库:物理存储的集合,包括数据文件、控制文件、重做日志文件等,它存储着所有的数据。
- 实例:一组 Oracle 后台进程和内存结构的集合,它负责管理数据库的打开和访问,一个实例只能打开一个数据库,但一个数据库可以被多个实例打开(RAC 环境)。
- 表空间:数据库的逻辑存储单元,一个或多个数据文件的集合,用户创建的对象(如表、索引)都存储在特定的表空间中,这实现了数据的物理隔离和管理。
关系:实例 加载并打开 数据库,数据库中的数据被组织在各个表空间中。
2 数据类型
| 类型 | 示例 | 描述 |
|---|---|---|
| 字符型 | VARCHAR2(size) |
可变长度字符串,最常用。 |
CHAR(size) |
定长字符串,存储时会在末尾填充空格。 | |
| 数值型 | NUMBER(p, s) |
p是总位数,s是小数位数。NUMBER(8,2)表示8位总数,2位小数。 |
| 日期型 | DATE |
存储日期和时间,精确到秒。 |
TIMESTAMP |
比 DATE 精度更高,可精确到小数秒。 |
|
| LOB型 | CLOB |
字符大对象,用于存储大量文本。 |
BLOB |
二进制大对象,用于存储图片、视频等。 |
3 表 的创建与管理
-- 创建表 (CREATE TABLE)
CREATE TABLE departments (
department_id NUMBER(4) PRIMARY KEY,
department_name VARCHAR2(30) NOT NULL,
location_id NUMBER(4)
);
-- 修改表结构 (ALTER TABLE)
-- 添加一列
ALTER TABLE employees ADD (job_id VARCHAR2(10));
-- 修改列的数据类型
ALTER TABLE employees MODIFY (first_name VARCHAR2(30));
-- 删除一列
ALTER TABLE employees DROP COLUMN job_id;
-- 删除表 (DROP TABLE) - 谨慎使用!
DROP TABLE employees;
4 约束
约束用于保证数据的完整性和一致性。
PRIMARY KEY:主键,唯一标识表中的每一行,不能为空。UNIQUE:唯一键,值必须唯一,但可以为空。NOT NULL:非空约束,列不能为空。FOREIGN KEY:外键,用于建立和加强两个表数据之间的链接,实现参照完整性。CHECK:检查约束,列必须满足特定条件。
-- 创建带有约束的表
CREATE TABLE countries (
country_id CHAR(2) PRIMARY KEY,
country_name VARCHAR2(40) NOT NULL
);
CREATE TABLE locations (
location_id NUMBER(4) PRIMARY KEY,
street_address VARCHAR2(40),
postal_code VARCHAR2(12),
city VARCHAR2(30) NOT NULL,
state_province VARCHAR2(25),
country_id CHAR(2),
CONSTRAINT fk_locations_countries FOREIGN KEY (country_id)
REFERENCES countries(country_id)
);
-- 添加约束
ALTER TABLE employees ADD CONSTRAINT fk_emp_dept FOREIGN KEY (department_id) REFERENCES departments(department_id);
5 索引
索引是一种用于快速查询数据的数据库对象,它类似于书籍的目录,可以大大提高 WHERE 子句的查询速度。
- 自动创建:在定义主键或唯一约束时,Oracle 会自动创建唯一索引。
- 手动创建:对于经常用于查询条件的列,可以手动创建索引。
-- 创建 B-Tree 索引 (最常用) CREATE INDEX idx_employees_lastname ON employees(last_name); -- 创建函数索引 (对列的函数结果建立索引) CREATE INDEX idx_employees_upper_name ON employees(UPPER(first_name));
注意:索引虽然能加速查询,但会降低
INSERT,UPDATE,DELETE的速度,并占用存储空间,只为必要的查询列创建索引。
6 视图
视图是一个虚拟表,其内容由查询定义,视图本身不存储数据,数据仍然在基表中。
- 优点:
- 简化复杂查询。
- 提供数据安全,隐藏基表的敏感列。
- 提供数据独立性。
-- 创建一个只显示员工姓名和薪水的视图 CREATE VIEW v_employee_salaries AS SELECT employee_id, first_name || ' ' || last_name AS full_name, salary FROM employees; -- 查询视图 SELECT * FROM v_employee_salaries WHERE salary > 5500;
7 序列 与同义词
-
序列:用于生成唯一数字的数据库对象,常用于主键。
CREATE SEQUENCE seq_employee_id START WITH 101 INCREMENT BY 1 NOCACHE; -- 使用序列 INSERT INTO employees (employee_id, ...) VALUES (seq_employee_id.NEXTVAL, ...); -
同义词:为对象(如表、视图、序列)创建一个别名,简化访问,或隐藏对象的实际所有者。
-- 创建公有同义词,所有用户都可以使用 CREATE PUBLIC SYNONYM emp FOR hr.employees; -- 现在可以直接用 emp 代替 hr.employees SELECT * FROM emp;
第三部分:数据操作与查询
1 DML (Data Manipulation Language) 详解
INSERT: 插入数据。INSERT INTO employees (employee_id, first_name, last_name, email, hire_date, salary, department_id) VALUES (seq_employee_id.NEXTVAL, 'Peter', 'Jones', 'peter.j@example.com', SYSDATE, 5500, 10);
UPDATE: 更新数据。强烈建议使用WHERE子句。UPDATE employees SET salary = salary * 1.1 WHERE department_id = 10;
DELETE: 删除数据。强烈建议使用WHERE子句。DELETE FROM employees WHERE employee_id = 102;
MERGE: 合并数据,根据条件决定是插入还是更新,非常高效。MERGE INTO employees e USING (SELECT employee_id, salary FROM temp_employees_updates) t ON (e.employee_id = t.employee_id) WHEN MATCHED THEN UPDATE SET e.salary = t.salary WHEN NOT MATCHED THEN INSERT (employee_id, salary) VALUES (t.employee_id, t.salary);
2 单表查询
SELECT 语句是 SQL 的核心。
-- 基本查询
SELECT employee_id, first_name, salary FROM employees;
-- 使用别名
SELECT employee_id AS "ID", first_name AS "Name", salary AS "Salary" FROM employees;
-- 使用 WHERE 过滤
SELECT * FROM employees WHERE salary > 5000 AND department_id = 20;
-- 使用 ORDER BY 排序
SELECT first_name, salary FROM employees ORDER BY salary DESC; -- 降序
SELECT first_name, salary FROM employees ORDER BY salary ASC; -- 升序 (默认)
-- 使用 ROWNUM 实现分页 (Oracle 传统方式)
-- 注意:ROWNUM 必须在最后应用,且不能直接对 ROWNUM > N 进行筛选
SELECT * FROM (
SELECT a.*, ROWNUM AS rnum FROM (
SELECT employee_id, first_name, salary FROM employees ORDER BY salary DESC
) a WHERE ROWNUM <= 10
) WHERE rnum > 5;
3 多表连接查询
从多个表中获取关联数据。
- 内连接:只返回两个表中匹配条件的行。
SELECT e.first_name, e.salary, d.department_name FROM employees e INNER JOIN departments d ON e.department_id = d.department_id;
- 左外连接:返回左表(
FROM指定的表)的所有行,以及右表中匹配的行,如果右表没有匹配,则结果中右表的列为 NULL。SELECT e.first_name, d.department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id;
- 右外连接:与左外连接相反,返回右表的所有行。
SELECT e.first_name, d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id;
- 全外连接:返回两个表中的所有行,无论是否匹配。
SELECT e.first_name, d.department_name FROM employees e FULL JOIN departments d ON e.department_id = d.department_id;
4 分组与聚合
使用 GROUP BY 和聚合函数对数据进行分组统计。
| 聚合函数 | 描述 |
|---|---|
COUNT(*) |
计算行数 |
COUNT(column) |
计算某列非空值的数量 |
SUM(column) |
计算某列数值的总和 |
AVG(column) |
计算某列的平均值 |
MAX(column) |
计算某列的最大值 |
MIN(column) |
计算某列的最小值 |
-- 按部门分组,统计每个部门的人数和平均薪水
SELECT
d.department_name,
COUNT(e.employee_id) AS employee_count,
AVG(e.salary) AS average_salary
FROM
employees e
JOIN
departments d ON e.department_id = d.department_id
GROUP BY
d.department_name;
-- 使用 HAVING 过滤分组结果
-- HAVING 类似于 WHERE,但 WHERE 用于过滤行,HAVING 用于过滤组
SELECT
d.department_name,
COUNT(e.employee_id) AS employee_count
FROM
employees e
JOIN
departments d ON e.department_id = d.department_id
GROUP BY
d.department_name
HAVING
COUNT(e.employee_id) > 5;
5 子查询
嵌套在其他 SQL 语句(如 SELECT, INSERT, UPDATE, DELETE)中的 SELECT 语句。
- 单行子查询:返回一行一列。
-- 查询薪水比 "John Doe" 高的所有员工 SELECT first_name, salary FROM employees WHERE salary > (SELECT salary FROM employees WHERE first_name = 'John' AND last_name = 'Doe');
- 多行子查询:返回多行一列,需要使用
IN,ANY,ALL。-- 查询在 "New York" 或 "Boston" 工作的所有员工 SELECT first_name FROM employees WHERE department_id IN (SELECT department_id FROM departments WHERE location_id IN (1700, 1800));
- 相关子查询:子查询依赖于外部查询的值,执行效率较低,但功能强大。
-- 查询每个部门的最高薪水的员工 SELECT e1.first_name, e1.salary, e1.department_id FROM employees e1 WHERE e1.salary = ( SELECT MAX(e2.salary) FROM employees e2 WHERE e2.department_id = e1.department_id -- 关联条件 );
6 合并数据
UNION 和 UNION ALL 用于合并两个或多个 SELECT 语句的结果集。
UNION: 合并结果,并自动去除重复行。UNION ALL: 合并结果,不去除重复行,效率更高。
-- 查询所有员工和所有部门名称 SELECT first_name FROM employees UNION SELECT department_name FROM departments; -- 查询所有员工和所有部门名称(包含重复) SELECT first_name FROM employees UNION ALL SELECT department_name FROM departments;
第四部分:PL/SQL 编程
PL/SQL 是 Oracle 对 SQL 的过程化扩展,它允许在数据库中编写存储过程、函数、触发器等。
1 什么是 PL/SQL?
PL/SQL 将 SQL 的数据操作能力和传统编程语言的过程化结构(如变量、循环、条件判断)结合在一起,使得可以在数据库内部执行复杂的业务逻辑。
2 基本结构:声明、执行、异常
DECLARE
-- 声明部分:定义变量、游标等
v_emp_name employees.first_name%TYPE; -- %TYPE 使用列的数据类型
v_sal NUMBER(8, 2) := 0;
BEGIN
-- 执行部分:主要逻辑
SELECT first_name, salary INTO v_emp_name, v_sal
FROM employees
WHERE employee_id = 101;
DBMS_OUTPUT.PUT_LINE('员工姓名: ' || v_emp_name || ', 薪水: ' || v_sal);
EXCEPTION
-- 异常处理部分:处理错误
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('未找到员工ID为 101 的记录。');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('发生其他错误: ' || SQLERRM);
END;
/
注意:要在 SQL Developer 或 SQL*Plus 中看到
DBMS_OUTPUT的输出,需要先执行SET SERVEROUTPUT ON;。
3 变量与常量
- 变量:使用
VARIABLE_NAME TYPE [DEFAULT value];声明。 - 常量:使用
CONSTANT_NAME CONSTANT TYPE := value;声明。 - 记录类型:类似于结构体或 C 语言中的 struct。
DECLARE
v_counter NUMBER := 1;
pi CONSTANT NUMBER := 3.14159;
TYPE emp_rec_type IS RECORD (
fname employees.first_name%TYPE,
lname employees.last_name%TYPE,
sal employees.salary%TYPE
);
v_emp emp_rec_type;
BEGIN
v_counter := v_counter + 1;
SELECT first_name, last_name, salary INTO v_emp
FROM employees WHERE employee_id = 101;
DBMS_OUTPUT.PUT_LINE(v_emp.fname || ' ' || v_emp.lname);
END;
/
4 控制结构
-
IF 语句
IF v_sal > 6000 THEN DBMS_OUTPUT.PUT_LINE('高薪员工'); ELSIF v_sal > 4000 THEN DBMS_OUTPUT.PUT_LINE('中等薪水'); ELSE DBMS_OUTPUT.PUT_LINE('普通员工'); END IF; -
循环
-- 1. 基本循环 LOOP v_counter := v_counter + 1; EXIT WHEN v_counter > 5; END LOOP; -- 2. FOR 循环 FOR i IN 1..5 LOOP DBMS_OUTPUT.PUT_LINE(i); END LOOP; -- 3. WHILE 循环 WHILE v_counter < 10 LOOP v_counter := v_counter + 1; END LOOP;
5 游标
游标是一个指向 SQL 查询结果集的指针,它允许你逐行处理查询结果。
- 隐式游标:由 Oracle 自动为
DML语句(INSERT,UPDATE,DELETE)和单行SELECT语句创建,可以通过SQL%ROWCOUNT,SQL%FOUND等属性获取信息。 - 显式游标:用于处理多行
SELECT语句的结果。
DECLARE
CURSOR c_employees IS
SELECT first_name, salary FROM employees WHERE department_id = 20;
v_first_name employees.first_name%TYPE;
v_salary employees.salary%TYPE;
BEGIN
OPEN c_employees; -- 打开游标
LOOP
-- 从游标中获取一行数据
FETCH c_employees INTO v_first_name, v_salary;
EXIT WHEN c_employees%NOTFOUND; -- 当没有更多数据时退出
DBMS_OUTPUT.PUT_LINE(v_first_name || ': ' || v_salary);
END LOOP;
CLOSE c_employees; -- 关闭游标
END;
/
6 存储过程 与函数
存储过程:用于执行一系列操作,可以有输入输出参数,但没有返回值。
CREATE OR REPLACE PROCEDURE give_raise (
p_emp_id IN NUMBER,
p_raise_percent IN NUMBER
)
IS
BEGIN
UPDATE employees
SET salary = salary * (1 + p_raise_percent / 100)
WHERE employee_id = p_emp_id;
COMMIT;
DBMS_OUTPUT.PUT_LINE('已为员工 ' || p_emp_id || ' 加薪。');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('加薪失败: ' || SQLERRM);
END give_raise;
/
-- 调用存储过程
EXECUTE give_raise(101, 10);
函数:用于返回一个计算结果,必须包含 RETURN 子句。
CREATE OR REPLACE FUNCTION get_employee_name (
p_emp_id IN NUMBER
) RETURN VARCHAR2
IS
v_full_name VARCHAR2(50);
BEGIN
SELECT first_name || ' ' || last_name INTO v_full_name
FROM employees
WHERE employee_id = p_emp_id;
RETURN v_full_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN '员工不存在';
END get_employee_name;
/
-- 调用函数
SELECT get_employee_name(101) AS full_name FROM DUAL;
第五部分:数据库管理与维护
1 用户与权限管理
-
创建用户
CREATE USER scott IDENTIFIED BY tiger;
-
授予权限
-- 授予连接数据库的权限 GRANT CONNECT TO scott; -- 授予创建会话、表、视图的权限 GRANT RESOURCE TO scott; -- 授予对特定表的查询权限 GRANT SELECT ON employees TO scott; -- 授予所有权限 (谨慎使用) GRANT ALL PRIVILEGES TO scott;
-
撤销权限
REVOKE SELECT ON employees FROM scott;
2 表空间管理
- 创建表空间
CREATE TABLESPACE users_data DATAFILE 'C:\oradata\XE\USERS.DBF' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED;
- 将表空间分配给用户
ALTER USER scott DEFAULT TABLESPACE users_data; ALTER USER scott TEMPORARY TABLESPACE temp;
3 备份与恢复概述
Oracle 提供了多种备份和恢复策略,从简单的导出/导入到复杂的 RMAN (Recovery Manager) 备份。
- 数据泵导出/导入:用于逻辑备份和迁移。
- 导出:
expdp system/password DIRECTORY=dpump_dir DUMPFILE=exp_full.dmp FULL=Y
- 导入:
impdp system/password DIRECTORY=dpump_dir DUMPFILE=exp_full.dmp FULL=Y
- 导出:
- RMAN (Recovery Manager):用于物理备份,是生产环境的首选,它直接与数据库文件交互,速度快,功能强大。
4 数据导入导出
*SQLLoader (SQLLDR)**:用于将外部文件(如 CSV)的数据高速加载到 Oracle 表中。
第六部分:进阶主题
1 事务控制
事务是一个逻辑工作单元,它由一个或多个 SQL 语句组成,这些语句要么全部成功,要么全部失败。
COMMIT: 提交事务,使更改永久生效。ROLLBACK: 回滚事务,撤销未提交的更改。SAVEPOINT: 在事务中设置一个保存点,可以部分回滚。
INSERT INTO ...; -- 未提交 SAVEPOINT sp1; UPDATE ...; -- 未提交 ROLLBACK TO sp1; -- 回滚到 sp1,撤销 UPDATE 之后的操作,但 INSERT 仍然有效 COMMIT; -- 最终提交 INSERT
2 性能优化基础
-
SQL Trace: 分析 SQL 语句的执行计划。
-
Explain Plan: 查看查询的执行计划,了解 Oracle 如何访问数据。
EXPLAIN PLAN FOR SELECT * FROM employees WHERE last_name = 'King'; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-
索引优化: 确保查询条件列上有合适的索引。
-
避免全表扫描: 尽量让查询使用索引。
3 Oracle 12c/19c/21c 新特性简介
- Oracle 12c: 引入了 多租架构,允许在一个容器数据库 中创建多个可插拔数据库,大大简化了数据库的创建和管理。
- Oracle 19c: 12.2 的稳定版,引入了 自动索引 等自优化特性。
- Oracle 21c: 增加了对 JSON-Schema 的原生支持,以及许多 AI 和机器学习相关的功能。
第七部分:学习资源与总结
学习资源
- 官方文档: Oracle Documentation 是最权威、最全面的学习资料。
- Oracle Learning Library: Oracle Learning Library 提供大量免费的在线课程和教程。
- Oracle Live SQL: Oracle Live SQL 一个在线的 Oracle 数据库环境,无需安装即可学习和练习 SQL 和 PL/SQL。
- 社区和论坛:
- Oracle Community
- Stack Overflow (标签:
oracle,plsql)
本教程为你提供了一个 Oracle 数据库的完整学习路径,从最基础的连接和查询,到核心的数据库对象,再到强大的 PL/SQL 编程和基础的管理知识,涵盖了成为一名合格的 Oracle 开发者或 DBA 所需的大部分技能。
学习建议:
- 动手实践:数据库是实践性极强的技术,多写、多练、多试错是最好的学习方式。
- 循序渐进:不要急于求成,先扎实掌握 SQL 和 PL/SQL 基础。
- 善用工具:熟练使用 SQL Developer 等工具能极大提高效率。
- 阅读官方文档:养成查阅官方文档的习惯,这是解决疑难问题的最佳途径。
祝你在 Oracle 数据库的学习之路上取得成功!
