SQL语言基础详解:语法、使用方法与综合案例
SQL(Structured Query Language)是用于管理关系型数据库的标准语言。本章系统讲解 SQL 语言的基础知识,包括其分类、编写规则、数据查询、函数使用、子查询、DML 操作等,并结合 Oracle 数据库环境提供详细示例和综合性实战。
一、SQL语言简介与特点
1. SQL 简介
- SQL 是 ANSI/ISO 标准的数据库查询与操作语言。
- 最早由 IBM 在 1970 年代开发(SEQUEL),后被 Oracle 等厂商广泛采用。
- 在 Oracle 中,SQL 与 PL/SQL 结合使用,支持复杂业务逻辑。
2. SQL 语言特点
| 特点 | 说明 |
|---|---|
| 非过程化 | 用户只需说明"做什么",无需指定"怎么做" |
| 统一性 | DDL、DML、DCL 均用 SQL 实现 |
| 高度可读 | 语法接近自然语言(如 SELECT ... FROM ... WHERE) |
| 跨平台 | 支持多种数据库(Oracle、MySQL、PostgreSQL 等) |
二、SQL语言的分类
| 类别 | 全称 | 功能 | 常见语句 |
|---|---|---|---|
| DDL | Data Definition Language | 定义数据库结构 | CREATE, ALTER, DROP |
| DML | Data Manipulation Language | 操作表中数据 | SELECT, INSERT, UPDATE, DELETE |
| DCL | Data Control Language | 控制权限与事务 | GRANT, REVOKE, COMMIT, ROLLBACK |
| TCL | Transaction Control Language | 事务控制 | COMMIT, ROLLBACK, SAVEPOINT |
本章重点讲解 DML(尤其是 SELECT)和部分 DDL/DCL。
三、SQL语言编写规则(Oracle)
-
大小写不敏感 :
SELECT与select等效(但字符串值区分大小写)。 -
语句以分号
;或/结束(在 SQL*Plus 中)。 -
关键字建议大写,提高可读性。
-
对象名(表、列)默认大写,若用小写需加双引号(不推荐)。
-
注释方式:
sql-- 单行注释 /* 多行注释 */
四、用户模式(Schema)与模式对象
1. 什么是模式(Schema)?
- 模式是数据库对象(表、视图、索引等)的集合,属于一个数据库用户。
- 用户名 = 模式名(如
SCOTT用户拥有SCOTT模式)。
2. 模式对象示例
| 对象类型 | 说明 |
|---|---|
| 表(Table) | 存储数据的基本单位 |
| 视图(View) | 虚拟表,基于 SQL 查询 |
| 索引(Index) | 加速查询 |
| 序列(Sequence) | 生成唯一数字 |
| 同义词(Synonym) | 对象别名 |
3. 示例模式:SCOTT
Oracle 自带的经典教学模式,包含以下表:
| 表名 | 说明 |
|---|---|
EMP |
员工表 |
DEPT |
部门表 |
SALGRADE |
工资等级表 |
BONUS |
奖金表(通常为空) |
启用 SCOTT 模式(Oracle 12c+)
sql
-- 以 sysdba 登录
CONNECT / AS SYSDBA
-- 解锁 scott 用户并设置密码
ALTER USER scott ACCOUNT UNLOCK IDENTIFIED BY tiger;
-- 连接 scott
CONNECT scott/tiger
若未安装 SCOTT 表,可手动运行
$ORACLE_HOME/rdbms/admin/scott.sql脚本。
五、检索数据(SELECT 语句详解)
1. 简单查询(SELECT ... FROM)
sql
-- 查询所有员工姓名和职位
SELECT ename, job
FROM emp;
-- 使用 * 查询所有列(不推荐用于生产)
SELECT * FROM dept;
2. 筛选查询(WHERE 子句)
sql
-- 查询工资大于 2000 的员工
SELECT ename, sal
FROM emp
WHERE sal > 2000;
-- 多条件筛选
SELECT ename, job, hiredate
FROM emp
WHERE deptno = 20 AND job = 'ANALYST';
3. 排序查询(ORDER BY)
sql
-- 按工资降序排列
SELECT ename, sal
FROM emp
ORDER BY sal DESC;
-- 多列排序:先按部门升序,再按工资降序
SELECT deptno, ename, sal
FROM emp
ORDER BY deptno ASC, sal DESC;
4. 分组查询(GROUP BY + HAVING)
sql
-- 统计每个部门的平均工资
SELECT deptno, AVG(sal) AS avg_salary
FROM emp
GROUP BY deptno;
-- 筛选平均工资 > 2000 的部门
SELECT deptno, AVG(sal) AS avg_salary
FROM emp
GROUP BY deptno
HAVING AVG(sal) > 2000;
⚠️ 注意:
WHERE用于筛选行,HAVING用于筛选分组。
5. 多表关联查询(JOIN)
sql
-- 内连接:查询员工及其部门名称
SELECT e.ename, e.job, d.dname
FROM emp e
INNER JOIN dept d ON e.deptno = d.deptno;
-- 左外连接:显示所有部门,即使没有员工
SELECT d.dname, e.ename
FROM dept d
LEFT JOIN emp e ON d.deptno = e.deptno;
-- Oracle 旧式写法(不推荐)
SELECT e.ename, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno;
六、Oracle常用系统函数
1. 字符类函数
| 函数 | 说明 | 示例 |
|---|---|---|
UPPER(str) |
转大写 | UPPER('scott') → 'SCOTT' |
LOWER(str) |
转小写 | LOWER('KING') → 'king' |
SUBSTR(str, pos, len) |
截取子串 | SUBSTR('ORACLE', 2, 3) → 'RAC' |
LENGTH(str) |
字符长度 | LENGTH('Hello') → 5 |
TRIM(str) |
去除空格 | TRIM(' abc ') → 'abc' |
sql
-- 示例:格式化员工姓名为大写
SELECT UPPER(ename) AS "Employee Name"
FROM emp;
2. 数字类函数
| 函数 | 说明 |
|---|---|
ROUND(n, d) |
四舍五入(d 为小数位) |
TRUNC(n, d) |
截断(不四舍五入) |
MOD(m, n) |
取余 |
ABS(n) |
绝对值 |
sql
-- 计算每人奖金(假设佣金为 10%)
SELECT ename, sal, NVL(comm, 0) AS commission,
ROUND(sal * 0.1 + NVL(comm, 0), 2) AS total_bonus
FROM emp;
3. 日期和时间类函数
| 函数 | 说明 |
|---|---|
SYSDATE |
当前系统日期时间 |
ADD_MONTHS(date, n) |
加 n 个月 |
MONTHS_BETWEEN(d1, d2) |
两日期间月数 |
TO_CHAR(date, fmt) |
日期转字符串 |
sql
-- 查询入职超过 40 年的员工(截至 2026 年)
SELECT ename, hiredate,
ROUND(MONTHS_BETWEEN(SYSDATE, hiredate) / 12, 1) AS years_worked
FROM emp
WHERE MONTHS_BETWEEN(SYSDATE, hiredate) / 12 > 40;
4. 转换类函数
| 函数 | 说明 |
|---|---|
TO_CHAR(value, fmt) |
转字符串 |
TO_NUMBER(str) |
转数字 |
TO_DATE(str, fmt) |
转日期 |
NVL(expr1, expr2) |
若 expr1 为 NULL,返回 expr2 |
sql
-- 将工资格式化为货币字符串
SELECT ename, TO_CHAR(sal, '$99,999.99') AS formatted_salary
FROM emp;
5. 聚集函数(Aggregate Functions)
| 函数 | 说明 |
|---|---|
COUNT(*) |
行数 |
SUM(col) |
求和 |
AVG(col) |
平均值 |
MAX(col) |
最大值 |
MIN(col) |
最小值 |
sql
-- 统计员工总数、最高/最低工资、平均工资
SELECT
COUNT(*) AS total_employees,
MAX(sal) AS max_salary,
MIN(sal) AS min_salary,
AVG(sal) AS avg_salary
FROM emp;
七、子查询(Subquery)
1. 什么是子查询?
- 在一个 SQL 语句中嵌套另一个
SELECT语句。 - 子查询先执行,结果作为外层查询的条件。
2. 单行子查询(返回一行一列)
sql
-- 查询工资高于平均工资的员工
SELECT ename, sal
FROM emp
WHERE sal > (SELECT AVG(sal) FROM emp);
3. 多行子查询(返回多行)
sql
-- 查询在 SALES 或 RESEARCH 部门工作的员工
SELECT ename, job
FROM emp
WHERE deptno IN (
SELECT deptno
FROM dept
WHERE dname IN ('SALES', 'RESEARCH')
);
-- 使用 ANY / ALL
SELECT ename, sal
FROM emp
WHERE sal > ANY (SELECT sal FROM emp WHERE deptno = 30); -- 高于销售部任一员工
4. 关联子查询(Correlated Subquery)
子查询引用外层查询的列。
sql
-- 查询每个部门中工资最高的员工
SELECT e1.ename, e1.deptno, e1.sal
FROM emp e1
WHERE e1.sal = (
SELECT MAX(e2.sal)
FROM emp e2
WHERE e2.deptno = e1.deptno -- 关联条件
);
八、操作数据库(DML 语句)
1. 插入数据(INSERT)
sql
-- 插入完整行
INSERT INTO dept (deptno, dname, loc)
VALUES (50, 'IT', 'BEIJING');
-- 插入部分列(其他列为 NULL 或默认)
INSERT INTO emp (empno, ename, job, hiredate, sal, deptno)
VALUES (8000, 'ALICE', 'DEVELOPER', SYSDATE, 5000, 50);
2. 更新数据(UPDATE)
sql
-- 给所有 ANALYST 加薪 10%
UPDATE emp
SET sal = sal * 1.1
WHERE job = 'ANALYST';
-- 更新多个字段
UPDATE emp
SET sal = 6000, comm = 500
WHERE empno = 8000;
3. 删除数据
DELETE(可回滚,触发器生效)
sql
-- 删除奖金为 NULL 的员工
DELETE FROM emp
WHERE comm IS NULL;
TRUNCATE(不可回滚,更快,不触发触发器)
sql
-- 清空 bonus 表
TRUNCATE TABLE bonus;
⚠️ 区别:
DELETE是 DML,可ROLLBACK;TRUNCATE是 DDL,自动COMMIT,不能回滚。
九、综合性实战案例
案例:生成"高绩效员工年度报告"
需求:
- 找出每个部门工资最高的员工;
- 显示其姓名、职位、工资、部门名、入职年限;
- 工资格式化为货币;
- 按部门编号排序;
- 输出到 SQL*Plus 报表。
sql
-- 设置 SQL*Plus 环境
SET PAGESIZE 40
SET LINESIZE 150
SET FEEDBACK OFF
TTITLE CENTER 'High Performer Annual Report - &SYSDATE' SKIP 2
BTITLE CENTER 'Confidential'
-- 格式化列
COLUMN ename HEADING "Employee Name" FORMAT A15
COLUMN job HEADING "Job Title" FORMAT A12
COLUMN dname HEADING "Department" FORMAT A15
COLUMN sal_fmt HEADING "Salary" FORMAT A12
COLUMN years HEADING "Years Worked" FORMAT 999.9
-- 主查询:使用关联子查询找部门最高薪员工
SELECT
e.ename,
e.job,
d.dname,
TO_CHAR(e.sal, '$99,999.99') AS sal_fmt,
ROUND(MONTHS_BETWEEN(SYSDATE, e.hiredate) / 12, 1) AS years
FROM emp e
JOIN dept d ON e.deptno = d.deptno
WHERE e.sal = (
SELECT MAX(sal)
FROM emp e2
WHERE e2.deptno = e.deptno
)
ORDER BY e.deptno;
-- 清理
TTITLE OFF
BTITLE OFF
SET FEEDBACK ON
输出效果(示例):
High Performer Annual Report - 14-JAN-2026
Employee Name Job Title Department Salary Years Worked
--------------- ------------ --------------- ------------ ------------
KING PRESIDENT ACCOUNTING $5,000.00 41.2
SCOTT ANALYST RESEARCH $3,000.00 40.8
BLAKE MANAGER SALES $2,850.00 41.0
十、总结
| 模块 | 核心知识点 |
|---|---|
| SQL 基础 | 分类、规则、模式概念 |
| 数据查询 | SELECT + WHERE + GROUP BY + ORDER BY + JOIN |
| 函数 | 字符、数字、日期、转换、聚集 |
| 子查询 | 单行、多行、关联 |
| DML | INSERT / UPDATE / DELETE / TRUNCATE |
💡 提示:掌握这些基础是进阶 PL/SQL、性能调优、数据库设计的前提。建议在 SQL*Plus 或 SQL Developer 中反复练习 SCOTT 模式下的各类查询。
✅ 附:快速启用 SCOTT 模式的完整脚本(若缺失)
sql
-- 以 sys 用户运行
@?/rdbms/admin/scott.sql
ALTER USER scott IDENTIFIED BY tiger ACCOUNT UNLOCK;