Appearance
前端开发者的 SQL 实战学习文档
更新: 6/28/2026 字数: 0 字 时长: 0 分钟
不讲运维、不讲调优黑魔法,只讲你对接后端、查业务库时真正用得上的那部分
作为前端,你不需要会搭主从、调缓冲池,但你大概率会遇到这些场景:自己查库核对数据、写个小后端接口、排查"为什么这条数据没显示"、给后端同学提需求时说清楚要哪些字段。这份文档就按这个目标来,从最基础的"表是什么"讲到日常最常用的查询、增删改,最后给你一份避坑清单。
一、先建立直觉:数据库里的"表"就是你熟悉的二维数组

别被"数据库"三个字吓到。用前端的语言翻译一下:
- 一个数据库(database)≈ 一个项目的数据仓库;
- 一张表(table)≈ 一个
Array<Object>,也就是你接口返回的那个列表; - 一行(row)≈ 数组里的一个对象
{ id: 1, name: '张三' }; - 一列(column)≈ 对象的某个字段(key),并且每列有固定类型(数字、字符串、时间等)。
你页面上渲染的表格、列表,几乎都来自某张表里的若干行。理解了这个映射,后面的 SQL 就只是"用另一种语法操作这个数组"而已。
几个高频字段类型,知道就行:
| 类型 | 对应 JS | 说明 |
|---|---|---|
INT / BIGINT | number | 整数,主键 id 常用 |
VARCHAR(n) | string | 变长字符串,n 是最大长度 |
TEXT | string | 长文本,比如文章内容 |
DECIMAL | number | 精确小数,金额必用(别用 float) |
DATETIME / TIMESTAMP | string/Date | 时间 |
TINYINT(1) | boolean | 0/1 表示真假 |
坑点:金额、价格永远别用
FLOAT/DOUBLE,浮点精度会让0.1 + 0.2 ≠ 0.3的问题搬到数据库里。用DECIMAL(10,2)。
二、SELECT:查数据,你 80% 的时间都在干这个

SELECT 就是"从表里取数据"。最基础的形态:
sql
-- 取 users 表的所有列、所有行
SELECT * FROM users;
-- 只取需要的列(推荐这么写)
SELECT id, name, email FROM users;* 表示所有列。开发里强烈建议只写你要的列,原因后面避坑章节细说。
可以给列起别名,方便前端拿到想要的字段名:
sql
SELECT name AS userName, created_at AS createdTime FROM users;坑点:SQL 里字符串和"等于"判断用单引号
'张三',不是双引号。=是判断相等(不是==)。这两点最容易让前端栽跟头。
三、WHERE + ORDER BY + LIMIT:筛选、排序、分页三件套

这三个是做列表页的标配,几乎对应你每个"带搜索、带排序、带翻页"的接口。
WHERE:按条件筛选
sql
-- 单条件
SELECT * FROM users WHERE status = 1;
-- 多条件组合
SELECT * FROM users WHERE status = 1 AND age > 18;
-- 范围、枚举、模糊
SELECT * FROM users WHERE age BETWEEN 18 AND 30;
SELECT * FROM users WHERE id IN (1, 2, 3);
SELECT * FROM users WHERE name LIKE '张%'; -- 以"张"开头常用运算符:= != > < >= <=、AND OR、IN、BETWEEN、LIKE(% 匹配任意多字符,_ 匹配单字符)。
坑点 1:判断"空"不能用
= NULL,必须用IS NULL/IS NOT NULL。NULL在 SQL 里是个特殊存在,和任何值(包括它自己)比较都不为真。 坑点 2:LIKE '%关键词%'(前面带%)会让索引失效,数据量大时很慢。做模糊搜索别滥用。
ORDER BY:排序
sql
SELECT * FROM users ORDER BY created_at DESC; -- 时间倒序,最新在前
SELECT * FROM users ORDER BY age ASC, id DESC; -- 多字段排序DESC 降序,ASC 升序(默认)。
LIMIT:分页(前端最关心)
sql
-- 取前 10 条
SELECT * FROM users LIMIT 10;
-- 分页:跳过 20 条,再取 10 条(即第 3 页,每页 10 条)
SELECT * FROM users LIMIT 10 OFFSET 20;
-- MySQL 也可写成 LIMIT 20, 10 (注意:是 offset 在前)前端分页的 pageNum / pageSize 换算公式:
OFFSET = (pageNum - 1) * pageSize
LIMIT = pageSize坑点:
LIMIT 100000, 10这种深翻页会越翻越慢(数据库要先扫过前 10 万行)。海量数据分页一般改用"记住上一页最后一个 id,WHERE id > lastId LIMIT 10"的游标方式——这点了解即可,真遇到和后端沟通。
四、JOIN:多表关联,搞懂这个你就超过一半前端了

真实业务里数据是拆开存的:用户信息在 users 表,订单在 orders 表,订单里只存一个 user_id 指向用户。要把"订单 + 下单人姓名"一起查出来,就得用 JOIN 把两张表拼起来。
sql
-- 查每个订单,以及对应的用户名
SELECT
orders.id,
orders.amount,
users.name AS userName
FROM orders
INNER JOIN users ON orders.user_id = users.id;ON 后面是"两张表靠哪个字段关联",这里是 orders.user_id = users.id。
两种最常用的 JOIN,理解差异即可:
| 类型 | 效果 | 场景 |
|---|---|---|
INNER JOIN | 只返回两边都匹配上的行(交集) | 订单一定有用户,用这个 |
LEFT JOIN | 保留左表所有行,右表没匹配到的填 NULL | 查"用户及其订单(可能没订单)"用这个 |
sql
-- 查所有用户,哪怕他一个订单都没有
SELECT users.name, orders.id AS orderId
FROM users
LEFT JOIN orders ON users.id = orders.user_id;坑点 1:多表查询时,两张表可能有同名列(比如都叫
id),一定要用表名.列名或别名区分,否则报"字段歧义"错误。 坑点 2:LEFT JOIN后如果在WHERE里写右表的条件(如WHERE orders.status = 1),会把没匹配上的NULL行过滤掉,效果退化成INNER JOIN。这类条件应写在ON里。
五、GROUP BY + 聚合函数:统计类需求的核心

凡是"统计""每个××的数量/总和""排行榜"这类需求,都靠 GROUP BY + 聚合函数。
常用聚合函数:COUNT() 计数、SUM() 求和、AVG() 平均、MAX()/MIN() 最值。
sql
-- 总共有多少用户
SELECT COUNT(*) FROM users;
-- 每个状态各有多少用户(分组统计)
SELECT status, COUNT(*) AS num
FROM users
GROUP BY status;
-- 每个用户的订单总金额
SELECT user_id, SUM(amount) AS total
FROM orders
GROUP BY user_id;如果要对"分组后的结果"再做筛选,用 HAVING(不是 WHERE):
sql
-- 找出下单总金额超过 1000 的用户
SELECT user_id, SUM(amount) AS total
FROM orders
GROUP BY user_id
HAVING total > 1000;坑点 1:
WHERE在分组前过滤原始行,HAVING在分组后过滤统计结果。顺序记牢:WHERE → GROUP BY → HAVING。 坑点 2:用了GROUP BY后,SELECT里只能出现"分组字段"和"聚合函数"。写个没分组又没聚合的普通列,有些数据库报错,有些返回不可预期的值。
六、INSERT / UPDATE / DELETE:写数据,慎之又慎

查询出错最多是查不到,写数据出错可能是线上事故。这三个语句务必小心。
INSERT:新增
sql
INSERT INTO users (name, email, status)
VALUES ('张三', 'zhang@test.com', 1);
-- 一次插多条
INSERT INTO users (name, email) VALUES
('李四', 'li@test.com'),
('王五', 'wang@test.com');UPDATE:修改
sql
UPDATE users SET status = 0 WHERE id = 5;
-- 同时改多个字段
UPDATE users SET name = '张三丰', status = 1 WHERE id = 5;DELETE:删除
sql
DELETE FROM users WHERE id = 5;⚠️ 头号大坑(必须吃透):
UPDATE和DELETE一定要带WHERE!DELETE FROM users;会清空整张表,UPDATE users SET status = 0;会把所有人改掉。这是最经典、最致命的事故。自保习惯:写更新/删除前,先用相同的
WHERE写一条SELECT确认"我要操作的就是这几行",确认无误再把SELECT *换成DELETE或UPDATE。sqlSELECT * FROM users WHERE id = 5; -- 先确认范围 DELETE FROM users WHERE id = 5; -- 再执行
七、前端写 SQL 的避坑清单(重点收藏)

把前面散落的坑点汇总成一份可对照的清单,写 SQL 前过一遍:
安全相关(最重要)
- 永远用参数化查询,杜绝字符串拼接。绝不要把用户输入直接拼进 SQL,否则就是 SQL 注入漏洞。js
// ❌ 危险:拼接 db.query(`SELECT * FROM users WHERE name = '${input}'`); // ✅ 正确:参数化(占位符由驱动转义) db.query('SELECT * FROM users WHERE name = ?', [input]); - 写库操作(UPDATE/DELETE)务必带
WHERE,并先用SELECT验证范围。
性能相关
- 别用
SELECT *,明确列出需要的字段——减少传输量,也避免后端加字段时把敏感信息(如密码)带给前端。 - 查询尽量带
LIMIT,尤其是不确定数据量时,防止一次拉回几十万行把服务和页面拖垮。 - 慎用前置模糊匹配
LIKE '%xx%'和深翻页LIMIT 大offset,数据量大时性能差,必要时找后端用其他方案。
正确性相关
- 判空用
IS NULL/IS NOT NULL,不能用= NULL。 - 金额用
DECIMAL,不要用浮点类型。 - 时间、时区注意统一,数据库存的时间和前端展示的时区可能不一致,跟后端约定好格式(一般用 UTC 时间戳传输)。
WHERE与HAVING别用错:行级过滤用WHERE,分组后过滤用HAVING。
协作习惯
- 生产环境的库别直接动手改,尤其是写操作,走后端接口或让有权限的同学审核。能用只读账号查就用只读账号。
结尾:你需要掌握到什么程度
对前端来说,目标不是成为 SQL 专家,而是做到这几点就够用了:能独立查库核对数据、能看懂后端写的 SQL、能写出带筛选排序分页的查询、能安全地做简单增删改、知道哪些写法有坑会被 review 打回。
把本文的 SELECT + WHERE + ORDER BY + LIMIT + JOIN + GROUP BY 这条主线练熟,再把第七节的避坑清单刻进肌肉记忆,日常工作中的 SQL 需求基本都能从容应对。