引言
在数据库管理和应用开发中,SQL是不可或缺的核心技能。无论是简单的数据查询还是复杂的业务逻辑处理,都需要扎实的SQL功底。本文通过两个综合性的SQL练习题,带你系统学习SQL的各项重要功能。
第一题:数据库基础操作全解析
1.1 数据表创建与约束管理
需求分析:创建学生表,要求包含学号、姓名、性别、年龄、所在系字段,并设置相应的约束条件。
-- 创建学生表,包含多种约束类型
CREATE TABLE Student (
Sno VARCHAR(20) PRIMARY KEY, -- 学号,主键
Sname VARCHAR(50) UNIQUE NOT NULL, -- 姓名,唯一且非空
Ssex ENUM('男', '女') NOT NULL, -- 性别,枚举约束
Sage INT NOT NULL, -- 年龄
Sdept VARCHAR(50) DEFAULT '计算机' -- 所在系,默认值
);

技术要点解析:
-
主键约束 (PRIMARY KEY):确保学号的唯一性,每个学生有唯一标识
-
唯一约束 (UNIQUE):防止姓名重复,保证数据唯一性
-
枚举约束 (ENUM):限制性别只能输入'男'或'女',保证数据规范性
-
默认值 (DEFAULT):简化数据插入,提高开发效率
1.2 表结构修改技巧
业务场景:随着系统演进,需要调整字段数据类型以优化存储空间。
-- 修改年龄字段的数据类型
ALTER TABLE Student MODIFY Sage SMALLINT;
优化效果:
-
INT类型占用4字节,存储范围:-2,147,483,648 到 2,147,483,647 -
SMALLINT类型占用2字节,存储范围:-32,768 到 32,768 -
对于年龄字段,使用
SMALLINT完全足够且节省存储空间
1.3 索引设计与性能优化
业务需求:为选课表创建复合主键索引,提升查询性能。
-- 创建复合主键索引
CREATE UNIQUE INDEX SC_INDEX ON SC (Sno, Cno);
索引设计原则:
-
复合索引顺序:先学号后课程号,符合查询模式
-
唯一性保证:防止同一学生重复选同一门课程
-
查询优化:加速基于学号和课程号的联合查询
应用场景:
-- 以下查询将利用索引
SELECT * FROM SC WHERE Sno = '2023001';
SELECT * FROM SC WHERE Sno = '2023001' AND Cno = 'C001';
1.4 视图创建与数据抽象
业务需求:创建视图方便查询学生选课信息。
-- 创建学生选课信息视图
CREATE VIEW stu_info AS
SELECT s.Sname, s.Ssex, c.Cname, sc.Score
FROM Student s
JOIN SC sc ON s.Sno = sc.Sno
JOIN Course c ON sc.Cno = c.Cno;
视图的优势:
-
简化复杂查询:隐藏多表连接的复杂性
-
数据安全性:只暴露必要的字段信息
-
逻辑独立性:底层表结构变化不影响上层应用
使用示例:
-- 简单查询所有学生选课信息
SELECT * FROM stu_info;
-- 查询特定性别的学生选课情况
SELECT * FROM stu_info WHERE Ssex = '男';
第二题:存储过程与业务逻辑封装
2.1 部门平均工资统计存储过程
业务需求:创建存储过程统计指定部门的平均工资。
DELIMITER //
CREATE PROCEDURE avg_sal_a(
IN dept_name VARCHAR(50), -- 输入参数:部门名称
OUT avg_salary DECIMAL(10,2) -- 输出参数:平均工资
)
BEGIN
-- 计算指定部门的平均工资
SELECT AVG(salary) INTO avg_salary
FROM Employee
WHERE department = dept_name;
END//
DELIMITER ;
技术特点:
-
参数传递:使用IN参数接收输入,OUT参数返回结果
-
业务逻辑封装:将复杂计算逻辑封装在数据库中
-
代码复用:多个应用可以调用同一存储过程
调用示例:
-- 调用存储过程并获取结果
CALL avg_sal_a('上海中心', @a);
SELECT @a AS 上海中心平均工资;
2.2 部门最高工资查询存储过程
业务需求:根据员工姓名查询其所在部门的最高工资。
DELIMITER //
CREATE PROCEDURE get_dept_max_salary(
IN emp_name VARCHAR(50), -- 输入参数:员工姓名
OUT max_salary DECIMAL(10,2) -- 输出参数:部门最高工资
)
BEGIN
-- 子查询获取员工部门,再查询该部门最高工资
SELECT MAX(e.salary) INTO max_salary
FROM Employee e
WHERE e.department = (
SELECT department
FROM Employee
WHERE name = emp_name
);
END//
DELIMITER ;
设计思路:
-
子查询应用:先通过员工姓名查询所在部门
-
聚合函数:使用MAX函数计算部门最高工资
-
结果返回:通过OUT参数返回计算结果
调用测试:
-- 测试存储过程功能
CALL get_dept_max_salary('张三', @a);
SELECT @a AS 部门最高工资;
实战技巧与最佳实践
3.1 约束设计的思考
为什么需要约束?
-
数据完整性:防止无效数据进入系统
-
业务规则:在数据库层面保证业务规则执行
-
应用简化:减少应用层的校验逻辑
3.2 索引使用建议
创建索引的时机:
-
频繁作为查询条件的字段
-
经常需要排序的字段
-
表数据量较大时
避免过度索引:
-
索引会占用存储空间
-
影响数据插入、更新、删除性能
3.3 存储过程的优势
性能提升:
-
减少网络传输
-
预编译执行计划
维护便利:
-
业务逻辑集中管理
-
修改时不影响应用代码