第124集 SQL增删改查
一、课程导入
在前面的课程中,我们已经学习了SQLite数据库的基本操作和SQL基础语法。今天,我们将深入学习SQL的核心功能——增删改查(CRUD)操作。CRUD是数据库操作的四大基本功能,包括:
- Create(创建):向数据库表中插入新的数据记录
- Read(读取):从数据库表中查询数据
- Update(更新):修改数据库表中已有的数据记录
- Delete(删除):删除数据库表中的数据记录
这些操作是数据库编程中最常用的功能,掌握它们是成为数据库开发人员的必备技能。
二、增删改查的重要性
CRUD操作是数据库应用程序的核心,几乎所有与数据相关的应用都离不开这些操作。例如:
- 社交媒体应用中发布新帖子(Create)、查看他人帖子(Read)、编辑自己的帖子(Update)、删除不当内容(Delete)
- 电子商务网站中添加商品(Create)、查询商品(Read)、修改商品价格(Update)、下架商品(Delete)
- 学生管理系统中添加学生信息(Create)、查询学生成绩(Read)、更新学生档案(Update)、删除毕业学生(Delete)
三、Create(创建)操作详解
Create操作通过SQL的INSERT语句实现,用于向数据库表中插入新的数据记录。
3.1 基本插入语法
INSERT INTO 表名 (列1, 列2, 列3, ...) VALUES (值1, 值2, 值3, ...);示例:
INSERT INTO students (name, age, gender, email) VALUES ('张三', 18, '男', 'zhangsan@example.com');3.2 插入全部列
如果要插入表中的所有列,可以省略列名列表,但需要确保值的顺序与表结构中列的顺序一致。
INSERT INTO 表名 VALUES (值1, 值2, 值3, ...);示例:
-- 假设students表的列顺序为:id, name, age, gender, email
INSERT INTO students VALUES (1, '张三', 18, '男', 'zhangsan@example.com');3.3 批量插入
使用INSERT语句可以一次插入多条记录,这比逐条插入效率更高。
INSERT INTO 表名 (列1, 列2, ...) VALUES
(值1_1, 值1_2, ...),
(值2_1, 值2_2, ...),
...;示例:
INSERT INTO students (name, age, gender, email) VALUES
('李四', 19, '男', 'lisi@example.com'),
('王五', 20, '女', 'wangwu@example.com'),
('赵六', 21, '男', 'zhaoliu@example.com');3.4 插入默认值
如果表中的列设置了默认值,可以使用DEFAULT关键字来插入默认值。
INSERT INTO 表名 (列1, 列2) VALUES (值1, DEFAULT);示例:
-- 假设students表的created_at列有默认值CURRENT_TIMESTAMP
INSERT INTO students (name, age, created_at) VALUES ('孙七', 22, DEFAULT);3.5 从其他表插入数据
可以使用INSERT ... SELECT语句从一个表向另一个表插入数据。
INSERT INTO 目标表 (列1, 列2, ...)
SELECT 列1, 列2, ... FROM 源表 WHERE 条件;示例:
-- 从old_students表向new_students表插入年龄大于20的学生
INSERT INTO new_students (name, age, gender, email)
SELECT name, age, gender, email FROM old_students WHERE age > 20;四、Read(读取)操作详解
Read操作通过SQL的SELECT语句实现,用于从数据库表中查询数据。
4.1 基本查询语法
SELECT 列1, 列2, ... FROM 表名;示例:
-- 查询students表中所有学生的姓名和年龄
SELECT name, age FROM students;4.2 查询所有列
使用*可以查询表中的所有列。
SELECT * FROM 表名;示例:
-- 查询students表中所有学生的所有信息
SELECT * FROM students;4.3 条件查询
使用WHERE子句可以筛选满足特定条件的数据。
SELECT 列1, 列2, ... FROM 表名 WHERE 条件;示例:
-- 查询年龄大于20的学生
SELECT * FROM students WHERE age > 20;4.4 排序查询
使用ORDER BY子句可以对查询结果进行排序。
SELECT 列1, 列2, ... FROM 表名 ORDER BY 排序列 ASC|DESC;示例:
-- 按年龄降序查询学生
SELECT * FROM students ORDER BY age DESC;4.5 限制查询结果
使用LIMIT子句可以限制查询结果的数量。
SELECT 列1, 列2, ... FROM 表名 LIMIT 数量 OFFSET 偏移量;示例:
-- 查询年龄最大的3个学生
SELECT * FROM students ORDER BY age DESC LIMIT 3;
-- 查询第4到第6个学生(偏移量从0开始)
SELECT * FROM students ORDER BY id ASC LIMIT 3 OFFSET 3;4.6 去重查询
使用DISTINCT关键字可以去除查询结果中的重复记录。
SELECT DISTINCT 列1, 列2, ... FROM 表名;示例:
-- 查询students表中所有不同的性别
SELECT DISTINCT gender FROM students;4.7 聚合查询
使用聚合函数可以对数据进行统计计算。
SELECT 聚合函数(列) FROM 表名;常用聚合函数:
COUNT():计算记录数SUM():计算数值总和AVG():计算平均值MAX():找出最大值MIN():找出最小值
示例:
-- 计算学生总数
SELECT COUNT(*) FROM students;
-- 计算学生的平均年龄
SELECT AVG(age) FROM students;4.8 分组查询
使用GROUP BY子句可以将数据分组,然后对每组数据进行聚合计算。
SELECT 分组列, 聚合函数(列) FROM 表名 GROUP BY 分组列;示例:
-- 按性别分组,计算每个性别的学生人数
SELECT gender, COUNT(*) FROM students GROUP BY gender;4.9 分组后过滤
使用HAVING子句可以对分组后的结果进行过滤。
SELECT 分组列, 聚合函数(列) FROM 表名 GROUP BY 分组列 HAVING 条件;示例:
-- 按性别分组,计算每个性别的学生人数,并筛选出人数大于2的性别
SELECT gender, COUNT(*) FROM students GROUP BY gender HAVING COUNT(*) > 2;五、Update(更新)操作详解
Update操作通过SQL的UPDATE语句实现,用于修改数据库表中已有的数据记录。
5.1 基本更新语法
UPDATE 表名 SET 列1 = 值1, 列2 = 值2, ... WHERE 条件;示例:
-- 将张三的年龄修改为25
UPDATE students SET age = 25 WHERE name = '张三';5.2 批量更新
使用UPDATE语句可以一次更新多条记录,只需在WHERE子句中指定合适的条件。
示例:
-- 将所有18岁学生的年龄修改为19
UPDATE students SET age = 19 WHERE age = 18;5.3 基于其他列的值更新
可以使用表中其他列的值来更新指定列。
示例:
-- 将所有学生的年龄增加1
UPDATE students SET age = age + 1;5.4 安全更新的重要性
在使用UPDATE语句时,一定要加上WHERE子句,否则会更新表中的所有记录,这可能导致严重的数据损失。
-- 危险!这会更新students表中的所有记录
UPDATE students SET age = 20;5.5 使用事务确保更新的安全性
对于重要的更新操作,建议使用事务来确保数据的一致性和完整性。
示例:
BEGIN TRANSACTION;
UPDATE students SET age = 25 WHERE name = '张三';
UPDATE students SET age = 26 WHERE name = '李四';
COMMIT;六、Delete(删除)操作详解
Delete操作通过SQL的DELETE语句实现,用于删除数据库表中的数据记录。
6.1 基本删除语法
DELETE FROM 表名 WHERE 条件;示例:
-- 删除名为张三的学生
DELETE FROM students WHERE name = '张三';6.2 批量删除
使用DELETE语句可以一次删除多条记录,只需在WHERE子句中指定合适的条件。
示例:
-- 删除所有年龄大于30的学生
DELETE FROM students WHERE age > 30;6.3 清空表
使用DELETE FROM 表名可以删除表中的所有记录,但保留表结构。
示例:
-- 删除students表中的所有记录
DELETE FROM students;6.4 安全删除的重要性
与UPDATE语句类似,在使用DELETE语句时,一定要加上WHERE子句,否则会删除表中的所有记录。
-- 危险!这会删除students表中的所有记录
DELETE FROM students;6.5 使用事务确保删除的安全性
对于重要的删除操作,建议使用事务来确保数据的一致性和完整性。
示例:
BEGIN TRANSACTION;
DELETE FROM students WHERE id = 1;
DELETE FROM students WHERE id = 2;
COMMIT;七、Python中的CRUD操作示例
下面我们将学习如何在Python中使用sqlite3模块执行CRUD操作。
7.1 插入数据
import sqlite3
# 连接到SQLite数据库
conn = sqlite3.connect('school.db')
cursor = conn.cursor()
# 插入单条记录
cursor.execute('INSERT INTO students (name, age, gender, email) VALUES (?, ?, ?, ?)',
('张三', 18, '男', 'zhangsan@example.com'))
print(f"插入了 {cursor.rowcount} 条记录")
# 插入多条记录
students = [
('李四', 19, '男', 'lisi@example.com'),
('王五', 20, '女', 'wangwu@example.com'),
('赵六', 21, '男', 'zhaoliu@example.com')
]
cursor.executemany('INSERT INTO students (name, age, gender, email) VALUES (?, ?, ?, ?)', students)
print(f"批量插入了 {cursor.rowcount} 条记录")
# 提交事务
conn.commit()
# 关闭连接
cursor.close()
conn.close()7.2 查询数据
import sqlite3
# 连接到SQLite数据库
conn = sqlite3.connect('school.db')
cursor = conn.cursor()
# 查询所有学生
cursor.execute('SELECT * FROM students')
students = cursor.fetchall()
print("所有学生:")
for student in students:
print(student)
# 条件查询
cursor.execute('SELECT * FROM students WHERE age > 19')
old_students = cursor.fetchall()
print("\n年龄大于19的学生:")
for student in old_students:
print(student)
# 排序查询
cursor.execute('SELECT * FROM students ORDER BY age DESC')
sorted_students = cursor.fetchall()
print("\n按年龄降序排列的学生:")
for student in sorted_students:
print(student)
# 关闭连接
cursor.close()
conn.close()7.3 更新数据
import sqlite3
# 连接到SQLite数据库
conn = sqlite3.connect('school.db')
cursor = conn.cursor()
# 更新数据
cursor.execute('UPDATE students SET age = ? WHERE name = ?', (25, '张三'))
print(f"更新了 {cursor.rowcount} 条记录")
# 提交事务
conn.commit()
# 验证更新结果
cursor.execute('SELECT * FROM students WHERE name = ?', ('张三',))
student = cursor.fetchone()
print(f"更新后的张三信息: {student}")
# 关闭连接
cursor.close()
conn.close()7.4 删除数据
import sqlite3
# 连接到SQLite数据库
conn = sqlite3.connect('school.db')
cursor = conn.cursor()
# 删除数据
cursor.execute('DELETE FROM students WHERE name = ?', ('张三',))
print(f"删除了 {cursor.rowcount} 条记录")
# 提交事务
conn.commit()
# 验证删除结果
cursor.execute('SELECT * FROM students')
students = cursor.fetchall()
print(f"删除后剩余学生数量: {len(students)}")
for student in students:
print(student)
# 关闭连接
cursor.close()
conn.close()八、增删改查的最佳实践
- 使用参数化查询:避免SQL注入攻击
- 添加适当的WHERE子句:防止误操作影响所有记录
- 使用事务:确保数据的一致性和完整性
- 及时提交或回滚:避免长时间占用数据库资源
- 备份重要数据:在执行批量操作前先备份
- 使用索引:提高查询效率
- 优化查询:避免不必要的全表扫描
- 限制返回的数据量:使用LIMIT子句减少网络传输
九、常见错误和解决方案
SQL注入攻击
- 错误:直接拼接SQL语句
- 解决方案:使用参数化查询
更新或删除所有记录
- 错误:忘记添加WHERE子句
- 解决方案:始终添加WHERE子句,并在执行前仔细检查条件
数据类型不匹配
- 错误:插入或更新的数据类型与表结构不匹配
- 解决方案:确保数据类型一致,使用类型转换函数
主键冲突
- 错误:插入的记录主键值已存在
- 解决方案:使用自动增量主键,或检查主键值是否已存在
外键约束错误
- 错误:插入或更新的数据违反外键约束
- 解决方案:确保引用的外键值存在
十、课程总结
在本集课程中,我们详细学习了SQL的增删改查(CRUD)操作:
- Create:使用INSERT语句向数据库表中插入数据,包括单条插入、批量插入等
- Read:使用SELECT语句查询数据,包括条件查询、排序查询、聚合查询等
- Update:使用UPDATE语句修改数据,注意加上WHERE子句避免误操作
- Delete:使用DELETE语句删除数据,同样需要注意WHERE子句的使用
同时,我们还学习了Python中如何使用sqlite3模块执行这些操作,以及增删改查的最佳实践和常见错误的解决方案。
掌握增删改查是数据库编程的基础,希望同学们能够多做练习,熟练掌握这些操作。在后续的课程中,我们将学习如何连接MySQL等其他数据库,以及更高级的数据库操作技术。
十一、课后练习
创建一个员工表(id, name, department, salary, hire_date),包含以下字段:
- id:员工ID,主键,自动增量
- name:员工姓名,不允许为空
- department:部门名称
- salary:工资
- hire_date:入职日期,默认值为当前日期
向员工表中插入5条记录
查询工资大于5000的员工
查询每个部门的员工人数和平均工资
将部门为"技术部"的员工工资增加10%
删除入职日期超过5年的员工
使用Python实现上述所有操作,并添加适当的错误处理