Oracle SQL 基础完整指南
Oracle SQL 是管理和操作 Oracle 数据库的核心语言。本指南从基础到进阶,系统介绍最常用的 SQL 概念和操作。
一、基础查询(SELECT)
1.1 基本语法结构
sql
SELECT [DISTINCT] 列1, 列2, ...
FROM 表名
[WHERE 条件]
[ORDER BY 排序列];
1.2 简单查询示例
sql
-- 查询所有列
SELECT * FROM employees;
-- 查询指定列
SELECT employee_id, first_name, last_name, salary FROM employees;
-- 使用别名(AS可省略)
SELECT employee_id AS "员工编号", first_name || ' ' || last_name AS "姓名"
FROM employees;
-- 去除重复行
SELECT DISTINCT department_id FROM employees;
-- 查询常量(使用DUAL伪表)
SELECT 'Hello Oracle' AS greeting, 100*2 AS result FROM dual;
Oracle 特点 :|| 是字符串连接符,DUAL 是系统伪表,用于查询常量或表达式。
二、过滤数据(WHERE)
2.1 比较运算符
sql
SELECT * FROM employees WHERE salary > 10000;
SELECT * FROM employees WHERE hire_date >= DATE '2020-01-01';
SELECT * FROM employees WHERE job_id = 'IT_PROG';
SELECT * FROM employees WHERE commission_pct IS NOT NULL; -- 判断空值
2.2 逻辑运算符
sql
-- AND、OR、NOT
SELECT * FROM employees
WHERE department_id = 80 AND salary > 8000;
SELECT * FROM employees
WHERE department_id = 80 OR job_id = 'MANAGER';
SELECT * FROM employees
WHERE NOT commission_pct IS NULL;
2.3 范围与集合查询
sql
-- BETWEEN...AND(包含边界)
SELECT * FROM employees WHERE salary BETWEEN 5000 AND 8000;
-- IN(在集合中)
SELECT * FROM employees WHERE department_id IN (10, 20, 30);
-- LIKE(模糊匹配),%匹配任意字符,_匹配单个字符
SELECT * FROM employees WHERE first_name LIKE 'S%'; -- 以S开头
SELECT * FROM employees WHERE first_name LIKE '_a%'; -- 第二个字母是a
三、排序(ORDER BY)
sql
-- 默认升序(ASC)
SELECT * FROM employees ORDER BY salary;
-- 降序(DESC)
SELECT * FROM employees ORDER BY salary DESC;
-- 多列排序
SELECT * FROM employees
ORDER BY department_id ASC, salary DESC;
-- 按表达式排序
SELECT employee_id, salary*12 AS annual_salary
FROM employees
ORDER BY annual_salary DESC;
-- 按列位置排序(不推荐)
SELECT employee_id, first_name, salary FROM employees ORDER BY 3 DESC;
四、聚合函数与分组
4.1 常用聚合函数
sql
SELECT
COUNT(*) AS total_employees,
COUNT(commission_pct) AS with_commission, -- 不计NULL
SUM(salary) AS total_salary,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary
FROM employees;
4.2 GROUP BY 分组
sql
-- 按部门统计
SELECT
department_id,
COUNT(*) AS emp_count,
AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id;
-- 多列分组
SELECT department_id, job_id, COUNT(*) AS emp_count
FROM employees
GROUP BY department_id, job_id;
4.3 HAVING 过滤分组结果
sql
-- 注意:HAVING 在 GROUP BY 后执行,WHERE 在 GROUP BY 前执行
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 8000
ORDER BY avg_salary DESC;
关键区别 :WHERE 过滤行,HAVING 过滤分组。
五、多表连接(JOIN)
5.1 内连接(INNER JOIN)
sql
-- 查询员工及所在部门信息
SELECT e.employee_id, e.first_name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id;
-- 隐式内连接(Oracle旧语法,不推荐)
SELECT e.employee_id, e.first_name, d.department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id;
5.2 左外连接(LEFT JOIN)
sql
-- 查询所有部门,包括没有员工的部门
SELECT d.department_id, d.department_name, COUNT(e.employee_id) AS emp_count
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
5.3 右外连接(RIGHT JOIN)和全外连接(FULL JOIN)
sql
-- 右外连接
SELECT e.employee_id, d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.department_id;
-- 全外连接(Oracle支持FULL OUTER JOIN)
SELECT e.employee_id, d.department_name
FROM employees e
FULL OUTER JOIN departments d ON e.department_id = d.department_id;
5.4 自连接
sql
-- 查询员工及其经理
SELECT e.first_name AS employee, m.first_name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.employee_id;
5.5 交叉连接(CROSS JOIN)
sql
-- 生成笛卡尔积(慎用)
SELECT * FROM employees CROSS JOIN departments;
六、子查询
6.1 单行子查询
sql
-- 查询工资高于平均工资的员工
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
6.2 多行子查询
sql
-- 查询部门名称为'Sales'或'Marketing'的所有员工
SELECT * FROM employees
WHERE department_id IN (
SELECT department_id FROM departments
WHERE department_name IN ('Sales', 'Marketing')
);
-- 使用ANY/SOME
SELECT * FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 80);
-- 使用ALL
SELECT * FROM employees
WHERE salary > ALL (SELECT AVG(salary) FROM employees GROUP BY department_id);
6.3 相关子查询
sql
-- 查询工资高于本部门平均工资的员工
SELECT e1.first_name, e1.salary, e1.department_id
FROM employees e1
WHERE e1.salary > (
SELECT AVG(e2.salary)
FROM employees e2
WHERE e2.department_id = e1.department_id -- 与外层关联
);
七、集合操作
sql
-- UNION:并集(去重)
SELECT employee_id FROM employees WHERE department_id = 80
UNION
SELECT employee_id FROM employees WHERE salary > 10000;
-- UNION ALL:并集(保留重复)
SELECT employee_id FROM employees WHERE department_id = 80
UNION ALL
SELECT employee_id FROM employees WHERE salary > 10000;
-- INTERSECT:交集
SELECT employee_id FROM employees WHERE department_id = 80
INTERSECT
SELECT employee_id FROM employees WHERE salary > 10000;
-- MINUS:差集(Oracle特有,MySQL用NOT IN)
SELECT employee_id FROM employees WHERE department_id = 80
MINUS
SELECT employee_id FROM employees WHERE salary > 10000;
八、常用函数
8.1 字符串函数
sql
-- 连接
SELECT first_name || ' ' || last_name FROM employees;
-- 长度
SELECT LENGTH('Oracle SQL') FROM dual; -- 返回10
-- 大小写转换
SELECT UPPER('oracle'), LOWER('SQL'), INITCAP('hello world') FROM dual;
-- 截取
SELECT SUBSTR('Oracle SQL', 1, 6) FROM dual; -- 返回'Oracle'
-- 查找
SELECT INSTR('Oracle SQL', 'SQL') FROM dual; -- 返回8
-- 替换
SELECT REPLACE('Oracle SQL', 'SQL', 'Database') FROM dual;
-- 填充
SELECT LPAD('123', 5, '0'), RPAD('456', 5, '*') FROM dual; -- 返回'00123', '456**'
8.2 数值函数
sql
-- 四舍五入
SELECT ROUND(123.456, 2), ROUND(123.456, 0), ROUND(123.456, -2) FROM dual;
-- 向上/向下取整
SELECT CEIL(123.1), FLOOR(123.9) FROM dual;
-- MOD取模
SELECT MOD(10, 3) FROM dual; -- 返回1
-- TRUNC截断
SELECT TRUNC(123.456, 2), TRUNC(123.456) FROM dual;
8.3 日期函数
sql
-- 当前日期和时间
SELECT SYSDATE, SYSTIMESTAMP FROM dual;
-- 日期加减(单位:天)
SELECT SYSDATE + 1 AS tomorrow FROM dual; -- 加1天
SELECT SYSDATE - 1/24 AS one_hour_ago FROM dual; -- 减1小时
-- 月份加减
SELECT ADD_MONTHS(SYSDATE, 3) FROM dual; -- 加3个月
-- 月份差
SELECT MONTHS_BETWEEN(SYSDATE, hire_date) FROM employees;
-- 年月提取
SELECT EXTRACT(YEAR FROM SYSDATE) AS year,
EXTRACT(MONTH FROM SYSDATE) AS month,
EXTRACT(DAY FROM SYSDATE) AS day
FROM dual;
-- 日期格式化
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM dual;
8.4 转换函数
sql
-- 数字转字符串
SELECT TO_CHAR(1234567.89, 'L999,999,999.99') FROM dual; -- 本地货币格式
-- 字符串转数字
SELECT TO_NUMBER('12345') FROM dual;
-- 字符串转日期
SELECT TO_DATE('2023-12-25', 'YYYY-MM-DD') FROM dual;
-- 类型转换
SELECT CAST('123' AS NUMBER), CAST(SYSDATE AS VARCHAR2(20)) FROM dual;
九、数据操作(DML)
9.1 INSERT 插入
sql
-- 插入单行
INSERT INTO employees (employee_id, first_name, last_name, email, hire_date, job_id)
VALUES (101, 'John', 'Doe', 'JDOE', SYSDATE, 'IT_PROG');
-- 插入多行(Oracle 23c 支持,旧版需用 INSERT ALL)
INSERT INTO departments (department_id, department_name)
VALUES (280, 'Data Science'), (290, 'Cloud Engineering');
-- 从查询结果插入
INSERT INTO employees_archive
SELECT * FROM employees WHERE hire_date < DATE '2010-01-01';
9.2 UPDATE 更新
sql
-- 更新单列
UPDATE employees SET salary = salary * 1.1 WHERE employee_id = 101;
-- 更新多列
UPDATE employees
SET salary = salary * 1.1, commission_pct = 0.2
WHERE job_id = 'SA_MAN';
-- 基于子查询更新
UPDATE employees e
SET e.salary = (SELECT AVG(salary) FROM employees WHERE department_id = e.department_id)
WHERE e.job_id = 'MANAGER';
9.3 DELETE 删除
sql
-- 删除行
DELETE FROM employees WHERE employee_id = 101;
-- 基于子查询删除
DELETE FROM employees
WHERE department_id = (SELECT department_id FROM departments WHERE department_name = 'Temp');
-- 清空表(保留结构)
TRUNCATE TABLE employees_temp; -- 比 DELETE 快,不可回滚
9.4 MERGE 合并(Oracle独有)
sql
-- 根据条件插入或更新
MERGE INTO employees e
USING (SELECT 101 AS emp_id, 'Jane' AS f_name FROM dual) src
ON (e.employee_id = src.emp_id)
WHEN MATCHED THEN
UPDATE SET e.first_name = src.f_name
WHEN NOT MATCHED THEN
INSERT (employee_id, first_name, last_name)
VALUES (src.emp_id, src.f_name, 'Smith');
十、数据定义(DDL)
10.1 CREATE TABLE 创建表
sql
-- 基本建表
CREATE TABLE employees_temp (
employee_id NUMBER(6) PRIMARY KEY,
first_name VARCHAR2(20),
last_name VARCHAR2(25) NOT NULL,
email VARCHAR2(25) UNIQUE,
hire_date DATE DEFAULT SYSDATE,
salary NUMBER(8,2) CHECK (salary > 0),
department_id NUMBER(4),
CONSTRAINT emp_dept_fk FOREIGN KEY (department_id) REFERENCES departments(department_id)
);
-- 创建表时带约束
CREATE TABLE orders (
order_id NUMBER CONSTRAINT order_pk PRIMARY KEY,
customer_id NUMBER NOT NULL,
order_date DATE DEFAULT SYSDATE,
status VARCHAR2(20) CONSTRAINT status_check CHECK (status IN ('NEW', 'SHIPPED', 'CANCELLED'))
);
10.2 ALTER TABLE 修改表
sql
-- 添加列
ALTER TABLE employees ADD (phone_number VARCHAR2(20));
-- 修改列
ALTER TABLE employees MODIFY (first_name VARCHAR2(50));
-- 删除列
ALTER TABLE employees DROP COLUMN phone_number;
-- 添加约束
ALTER TABLE employees ADD CONSTRAINT emp_salary_check CHECK (salary > 0);
-- 删除约束
ALTER TABLE employees DROP CONSTRAINT emp_salary_check;
10.3 DROP TABLE 删除表
sql
-- 删除表
DROP TABLE employees_temp;
-- 级联删除(删除约束)
DROP TABLE departments CASCADE CONSTRAINTS;
10.4 CREATE INDEX 创建索引
sql
-- 单列索引
CREATE INDEX emp_last_name_idx ON employees(last_name);
-- 唯一索引
CREATE UNIQUE INDEX emp_email_idx ON employees(email);
-- 复合索引
CREATE INDEX emp_dept_salary_idx ON employees(department_id, salary);
-- 函数索引
CREATE INDEX emp_upper_name_idx ON employees(UPPER(first_name));
十一、约束(Constraints)
sql
-- 主键(PRIMARY KEY)
CONSTRAINT emp_pk PRIMARY KEY (employee_id)
-- 外键(FOREIGN KEY)
CONSTRAINT emp_dept_fk FOREIGN KEY (department_id) REFERENCES departments(department_id)
ON DELETE CASCADE -- 级联删除
ON UPDATE SET NULL -- 父表更新时设为NULL
-- 唯一(UNIQUE)
CONSTRAINT emp_email_uk UNIQUE (email)
-- 非空(NOT NULL)
last_name VARCHAR2(25) NOT NULL
-- 检查(CHECK)
CONSTRAINT emp_salary_check CHECK (salary > 0 AND salary < 999999)
-- 默认(DEFAULT)
hire_date DATE DEFAULT SYSDATE
十二、视图(VIEW)
sql
-- 创建视图
CREATE VIEW emp_details AS
SELECT e.employee_id, e.first_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE e.salary > 5000;
-- 使用视图
SELECT * FROM emp_details WHERE department_name = 'Sales';
-- 创建只读视图(WITH READ ONLY)
CREATE VIEW emp_readonly AS
SELECT * FROM employees
WITH READ ONLY;
-- 删除视图
DROP VIEW emp_details;
十三、事务控制(TCL)
13.1 自动提交与手动提交
sql
-- 查看自动提交状态(SQL*Plus)
SHOW AUTOCOMMIT;
-- 关闭自动提交
SET AUTOCOMMIT OFF;
13.2 事务操作
sql
-- 开始事务(Oracle自动开始)
UPDATE employees SET salary = 10000 WHERE employee_id = 101;
-- 保存点
SAVEPOINT update_salary;
-- 回滚到保存点
ROLLBACK TO update_salary;
-- 提交事务
COMMIT;
-- 回滚整个事务
ROLLBACK;
十四、Oracle 特有功能
14.1 伪列
sql
-- ROWNUM:行号(结果集序号,查询时动态生成)
SELECT * FROM employees WHERE ROWNUM <= 10; -- 取前10行
-- ROWID:物理地址(每行唯一)
SELECT ROWID, employee_id FROM employees;
-- 分页查询(ROWNUM方式)
SELECT * FROM (
SELECT e.*, ROWNUM rn FROM (
SELECT * FROM employees ORDER BY salary DESC
) e WHERE ROWNUM <= 20
) WHERE rn > 10; -- 第11-20行(第2页)
14.2 序列(SEQUENCE)
sql
-- 创建序列
CREATE SEQUENCE emp_seq
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
-- 使用序列
SELECT emp_seq.NEXTVAL FROM dual; -- 下一个值
SELECT emp_seq.CURRVAL FROM dual; -- 当前值
-- 插入时使用
INSERT INTO employees (employee_id, first_name)
VALUES (emp_seq.NEXTVAL, 'John');
14.3 同义词(SYNONYM)
sql
-- 创建同义词(简化对象访问)
CREATE SYNONYM emp FOR hr.employees;
-- 使用同义词
SELECT * FROM emp;
-- 删除同义词
DROP SYNONYM emp;
十五、常用查询技巧
15.1 分页查询(Oracle 12c+ 新语法)
sql
-- 推荐使用 OFFSET FETCH(Oracle 12c+)
SELECT * FROM employees
ORDER BY employee_id
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY; -- 第11-20行
15.2 递归查询(层次查询)
sql
-- 查询员工及其上级(树形结构)
SELECT
employee_id,
first_name,
manager_id,
LEVEL
FROM employees
START WITH manager_id IS NULL -- 从根节点开始
CONNECT BY PRIOR employee_id = manager_id; -- 递归条件
15.3 分析函数(窗口函数)
sql
-- 计算每个部门的工资排名
SELECT
employee_id,
department_id,
salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank,
AVG(salary) OVER (PARTITION BY department_id) AS dept_avg_salary
FROM employees;
十六、学习建议与路径
16.1 初学者必经阶段
- 基础查询:SELECT, WHERE, ORDER BY(1-2天)
- 多表连接:JOIN, 子查询(2-3天)
- 聚合分组:GROUP BY, HAVING(1天)
- 数据操作:INSERT, UPDATE, DELETE(1天)
- DDL操作:CREATE, ALTER, DROP(1天)
- 高级函数:字符串、日期、转换(2-3天)
- 事务与约束:事务控制、约束管理(1天)
16.2 进阶方向
- 分析函数与窗口函数
- PL/SQL 存储过程与函数
- 性能优化(索引、执行计划)
- 分区表与大表设计
- 闪回查询与数据恢复
16.3 实践建议
- ✅ 安装本地 Oracle XE 或 Docker 版本练习
- ✅ 使用 SQL*Plus 或 SQL Developer 工具
- ✅ 从简单的单表查询开始,逐步增加复杂度
- ✅ 理解执行计划(
EXPLAIN PLAN FOR) - ✅ 掌握常见错误代码及解决方法
总结
Oracle SQL 是一门强大而严谨的数据库语言。掌握基础后,建议深入学习 PL/SQL 编程和性能优化,这将极大提升企业级应用开发能力。记住:多练习、多思考、多优化是成为 SQL 专家的唯一路径。