欢迎来到MySQL系列教程的第3天!今天我们将学习SQL语句的基础操作,包括DDL(数据定义语言)、DML(数据操作语言)和DQL(数据查询语言)。这些将是日后最常用的SQL命令,务必熟练掌握。
文章目录
-
- 一、写在前面
- 二、DDL语句:数据库和表的操作
-
- [2.1 数据库操作](#2.1 数据库操作)
- [2.2 表操作:CREATE TABLE](#2.2 表操作:CREATE TABLE)
- [2.3 表操作:ALTER TABLE](#2.3 表操作:ALTER TABLE)
- [2.4 删除表](#2.4 删除表)
- 三、DML语句:数据的增删改
-
- [3.1 INSERT语句的多种写法](#3.1 INSERT语句的多种写法)
- [3.2 UPDATE的安全写法](#3.2 UPDATE的安全写法)
- [3.3 DELETE和TRUNCATE的区别](#3.3 DELETE和TRUNCATE的区别)
- 四、DQL基础:SELECT查询
-
- [4.1 SELECT * 的坑](#4.1 SELECT * 的坑)
- [4.2 别名和去重](#4.2 别名和去重)
- 五、实战:创建电商订单系统相关表
-
- [5.1 完整的电商表结构设计](#5.1 完整的电商表结构设计)
- [5.2 插入测试数据](#5.2 插入测试数据)
- 六、踩坑提醒
-
- [6.1 UPDATE忘记WHERE的悲剧](#6.1 UPDATE忘记WHERE的悲剧)
- [6.2 DELETE忘记WHERE的悲剧](#6.2 DELETE忘记WHERE的悲剧)
- 七、面试高频考点
- 八、总结
- 九、下一步预告
- 十、参考资料
- 互动话题
一、写在前面
SQL语句分为以下几类:
| 分类 | 全称 | 主要语句 | 用途 |
|---|---|---|---|
| DDL | Data Definition Language | CREATE, DROP, ALTER | 定义数据库结构 |
| DML | Data Manipulation Language | INSERT, UPDATE, DELETE | 操作数据 |
| DQL | Data Query Language | SELECT | 查询数据 |
| DCL | Data Control Language | GRANT, REVOKE | 权限控制 |
| TCL | Transaction Control Language | COMMIT, ROLLBACK | 事务控制 |
今天我们重点学习DDL、DML和DQL的基础用法。
二、DDL语句:数据库和表的操作
2.1 数据库操作
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS ecommerce
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE ecommerce;
-- 查看所有数据库
SHOW DATABASES;
-- 查看当前数据库
SELECT DATABASE();
-- 删除数据库(危险操作!)
DROP DATABASE IF EXISTS ecommerce;
-- 修改数据库字符集
ALTER DATABASE ecommerce CHARACTER SET utf8mb4;
经验之谈: 创建数据库时务必指定 utf8mb4 字符集,支持完整的Unicode(包括emoji)。
2.2 表操作:CREATE TABLE
sql
-- 创建用户表
CREATE TABLE IF NOT EXISTS users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
phone CHAR(11) COMMENT '手机号',
password VARCHAR(255) NOT NULL COMMENT '密码(加密存储)',
status TINYINT UNSIGNED DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_email (email),
INDEX idx_phone (phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
CREATE TABLE要点:
- 每个表建议有
id主键 - 常用查询字段加索引
- 必须设置字符集为utf8mb4
- 添加COMMENT注释,方便维护
2.3 表操作:ALTER TABLE
sql
-- 添加列
ALTER TABLE users ADD COLUMN nickname VARCHAR(50) COMMENT '昵称' AFTER username;
-- 修改列类型
ALTER TABLE users MODIFY COLUMN phone VARCHAR(20) COMMENT '手机号(支持国际号码)';
-- 修改列名(MySQL 8.0+)
ALTER TABLE users RENAME COLUMN nickname TO display_name;
-- 删除列
ALTER TABLE users DROP COLUMN display_name;
-- 添加索引
ALTER TABLE users ADD INDEX idx_created_at (created_at);
-- 删除索引
ALTER TABLE users DROP INDEX idx_created_at;
-- 修改表名
ALTER TABLE users RENAME TO sys_users;
RENAME TABLE sys_users TO users;
2.4 删除表
sql
-- 删除表(会删除数据和结构)
DROP TABLE IF EXISTS temp_table;
-- 清空表数据(保留结构)
TRUNCATE TABLE temp_table;
三、DML语句:数据的增删改
3.1 INSERT语句的多种写法
sql
-- 方式1:标准插入(推荐,明确指定列)
INSERT INTO users (username, email, phone, password)
VALUES ('zhangsan', 'zhangsan@example.com', '13800138000', 'encrypted_pwd');
-- 方式2:插入多行(性能更好)
INSERT INTO users (username, email, password) VALUES
('lisi', 'lisi@example.com', 'pwd1'),
('wangwu', 'wangwu@example.com', 'pwd2'),
('zhaoliu', 'zhaoliu@example.com', 'pwd3');
-- 方式3:使用SET语法
INSERT INTO users SET
username = 'sunqi',
email = 'sunqi@example.com',
password = 'pwd4';
-- 方式4:从其他表插入(数据迁移常用)
INSERT INTO users_backup (username, email)
SELECT username, email FROM users WHERE status = 0;
-- 方式5:存在则更新,不存在则插入(UPSERT)
INSERT INTO users (id, username, email)
VALUES (1, 'newname', 'new@example.com')
ON DUPLICATE KEY UPDATE
username = VALUES(username),
email = VALUES(email);
-- MySQL 8.0.19+ 新语法
INSERT INTO users (id, username, email)
VALUES (1, 'newname', 'new@example.com') AS new
ON DUPLICATE KEY UPDATE
username = new.username,
email = new.email;
经验之谈:
- 生产环境务必指定列名,不要依赖列顺序
- 批量插入比单条插入性能高很多
- 使用
INSERT IGNORE忽略重复键错误
3.2 UPDATE的安全写法
sql
-- 危险!忘记WHERE会更新所有行!
UPDATE users SET status = 0; -- 所有用户都被禁用了!
-- 安全的UPDATE写法(先查询确认)
-- 步骤1:先SELECT确认要更新的数据
SELECT * FROM users WHERE id = 1;
-- 步骤2:执行UPDATE(必须带WHERE)
UPDATE users
SET status = 0, updated_at = NOW()
WHERE id = 1;
-- 使用LIMIT限制更新数量(保险措施)
UPDATE users SET status = 0 WHERE status = 1 LIMIT 10;
-- 多表UPDATE
UPDATE users u
JOIN orders o ON u.id = o.user_id
SET u.order_count = u.order_count + 1
WHERE o.status = 'completed';
3.3 DELETE和TRUNCATE的区别
sql
-- DELETE:删除指定行,可以回滚,记录日志
DELETE FROM users WHERE id = 1;
-- DELETE忘记WHERE的补救:使用LIMIT
DELETE FROM users LIMIT 1; -- 只删1条
-- TRUNCATE:清空整个表,速度快,不可回滚
TRUNCATE TABLE temp_logs;
| 特性 | DELETE | TRUNCATE |
|---|---|---|
| 删除范围 | 可指定条件 | 全部数据 |
| 执行速度 | 较慢(逐行删除) | 很快(删除表重建) |
| 事务回滚 | 支持 | 不支持 |
| 触发器 | 会触发 | 不会触发 |
| 自增计数 | 保留 | 重置 |
| 日志记录 | 记录每行 | 最小日志 |
四、DQL基础:SELECT查询
4.1 SELECT * 的坑
sql
-- 不推荐:SELECT * 会返回所有列
SELECT * FROM users;
-- 推荐:明确指定需要的列
SELECT id, username, email, created_at FROM users;
-- 原因:
-- 1. 网络传输更多数据
-- 2. 可能包含敏感字段(password)
-- 3. 表结构变化会影响应用程序
-- 4. 无法利用覆盖索引优化
4.2 别名和去重
sql
-- 列别名(AS可省略)
SELECT
id AS user_id,
username AS name,
created_at AS register_time
FROM users;
-- 表别名(多表查询常用)
SELECT u.id, u.username FROM users u;
-- 去重DISTINCT
SELECT DISTINCT status FROM users; -- 查看有哪些状态值
-- 多列去重(组合唯一)
SELECT DISTINCT status, gender FROM users;
五、实战:创建电商订单系统相关表
5.1 完整的电商表结构设计
sql
-- 用户表
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
phone CHAR(11),
password VARCHAR(255) NOT NULL,
status TINYINT UNSIGNED DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_phone (phone)
) ENGINE=InnoDB COMMENT='用户表';
-- 商品表
CREATE TABLE products (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(200) NOT NULL COMMENT '商品名称',
description TEXT COMMENT '商品描述',
price DECIMAL(10, 2) NOT NULL COMMENT '售价',
stock INT UNSIGNED DEFAULT 0 COMMENT '库存',
status TINYINT UNSIGNED DEFAULT 1 COMMENT '0-下架 1-上架',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_status_price (status, price)
) ENGINE=InnoDB COMMENT='商品表';
-- 订单表
CREATE TABLE orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
order_no VARCHAR(32) NOT NULL UNIQUE COMMENT '订单编号',
user_id INT UNSIGNED NOT NULL COMMENT '用户ID',
total_amount DECIMAL(10, 2) NOT NULL COMMENT '订单总金额',
status TINYINT UNSIGNED DEFAULT 0 COMMENT '0-待支付 1-已支付 2-已发货 3-已完成 4-已取消',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_order_no (order_no),
INDEX idx_created_at (created_at),
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB COMMENT='订单表';
-- 订单商品表(订单明细)
CREATE TABLE order_items (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
order_id INT UNSIGNED NOT NULL COMMENT '订单ID',
product_id INT UNSIGNED NOT NULL COMMENT '商品ID',
product_name VARCHAR(200) NOT NULL COMMENT '商品名称(快照)',
price DECIMAL(10, 2) NOT NULL COMMENT '下单时价格',
quantity INT UNSIGNED NOT NULL COMMENT '数量',
subtotal DECIMAL(10, 2) NOT NULL COMMENT '小计金额',
INDEX idx_order_id (order_id),
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
) ENGINE=InnoDB COMMENT='订单商品表';
5.2 插入测试数据
sql
-- 插入用户
INSERT INTO users (username, email, phone, password) VALUES
('user001', 'user001@test.com', '13800138001', 'pwd001'),
('user002', 'user002@test.com', '13800138002', 'pwd002'),
('user003', 'user003@test.com', '13800138003', 'pwd003');
-- 插入商品
INSERT INTO products (name, description, price, stock) VALUES
('iPhone 15', '苹果最新手机', 5999.00, 100),
('MacBook Pro', '苹果笔记本电脑', 14999.00, 50),
('AirPods Pro', '无线耳机', 1999.00, 200);
-- 插入订单
INSERT INTO orders (order_no, user_id, total_amount, status) VALUES
('ORDER202401010001', 1, 5999.00, 1),
('ORDER202401010002', 1, 1999.00, 0),
('ORDER202401010003', 2, 14999.00, 2);
-- 插入订单明细
INSERT INTO order_items (order_id, product_id, product_name, price, quantity, subtotal) VALUES
(1, 1, 'iPhone 15', 5999.00, 1, 5999.00),
(2, 3, 'AirPods Pro', 1999.00, 1, 1999.00),
(3, 2, 'MacBook Pro', 14999.00, 1, 14999.00);
六、踩坑提醒
6.1 UPDATE忘记WHERE的悲剧
真实案例: 某运营人员执行了以下SQL:
sql
-- 本意:只禁用某个违规用户
UPDATE users SET status = 0;
-- 结果:所有用户都被禁用了!网站瘫痪!
防范措施:
- 执行UPDATE前先用SELECT确认
- 使用
SET sql_safe_updates = 1;开启安全模式 - UPDATE必须带WHERE条件
sql
-- 开启安全更新模式
SET sql_safe_updates = 1;
-- 此时执行无WHERE的UPDATE会报错
UPDATE users SET status = 0;
-- ERROR 1175 (HY000): You are using safe update mode...
6.2 DELETE忘记WHERE的悲剧
sql
-- 本意:删除测试数据
DELETE FROM orders;
-- 结果:所有订单都没了!
防范措施:
- 先用SELECT确认要删除的数据
- 使用事务,删除前可以回滚
- 重要数据先备份
sql
-- 安全的删除流程
START TRANSACTION;
SELECT * FROM orders WHERE status = 4; -- 确认要删除的已取消订单
DELETE FROM orders WHERE status = 4;
-- 确认无误后提交
COMMIT;
-- 如果有问题回滚
-- ROLLBACK;
七、面试高频考点
考点1:DELETE和TRUNCATE的区别?
答案:
- DELETE是DML语句,TRUNCATE是DDL语句
- DELETE可以带WHERE条件删除部分数据,TRUNCATE只能清空全部
- DELETE逐行删除,记录日志,可以回滚;TRUNCATE直接删除表重建,速度快,不可回滚
- DELETE会触发表上的触发器,TRUNCATE不会
- DELETE保留自增计数,TRUNCATE重置自增计数
考点2:DROP和DELETE的区别?
答案:
- DROP是DDL语句,删除整个表(结构和数据)
- DELETE是DML语句,只删除数据,保留表结构
- DROP不可回滚,DELETE在事务中可以回滚
考点3:INSERT的几种写法?
答案:
INSERT INTO table (cols) VALUES (...)- 标准插入INSERT INTO table VALUES (...)- 省略列名(不推荐)INSERT INTO table SET col1=val1, col2=val2- SET语法INSERT INTO table SELECT ...- 从其他表插入INSERT ... ON DUPLICATE KEY UPDATE- 存在更新,不存在插入
考点4:如何防止UPDATE/DELETE误操作?
答案:
- 开启sql_safe_updates安全模式
- 执行前先SELECT确认
- 使用事务,先执行后确认再提交
- 重要操作先在测试环境验证
- 定期备份数据
八、总结
今天我们学习了:
- DDL语句:CREATE/DROP/ALTER操作数据库和表结构
- DML语句:INSERT/UPDATE/DELETE操作数据
- DQL语句:SELECT基础查询
- 实战:创建了电商系统的核心表
核心要点:
- 创建表要设置utf8mb4字符集
- UPDATE/DELETE必须带WHERE条件
- SELECT不要直接用*,指定需要的列
- 重要操作前先备份,使用事务保护
九、下一步预告
Day4:MySQL条件查询与排序
我们将学习:
- WHERE子句的各种条件写法
- NULL值的处理
- ORDER BY排序技巧
- LIMIT分页实现
- 电商系统的各种查询场景
十、参考资料
互动话题
- 你在工作中有没有遇到过UPDATE/DELETE忘记WHERE的惊险时刻?后来怎么解决的?
- 你们公司的数据库表设计规范有哪些?欢迎在评论区分享!
- 对于电商系统的表设计,你有什么优化建议?
如果觉得有帮助,请点赞+收藏+关注!我们Day4见!
