SQL零基础入门:这10个语句解决80%的数据查询问题(超详细代码注释)
2026/4/27 9:03:33 网站建设 项目流程

前言

大家好,我是船长。

做了近10年数据分析,我发现一个规律:SQL虽然语句很多,但日常工作中真正高频用到的,不超过10类。

今天这篇文章,我把这10类语句全部梳理出来,每一类都配上真实业务场景和完整代码注释。

不管你是完全零基础,还是学了一半卡住的,看完这篇,80%的数据查询需求都能解决。

文章用的是 MySQL 语法,其他数据库(PostgreSQL、SQLite、Oracle)大同小异,关键差异处会单独说明。


一、SELECT + FROM:最基础的数据读取

SQL的核心就是"告诉数据库:从哪张表,取哪些列"。

-- 查询 users 表的全部数据(不推荐,数据量大时会很慢) SELECT * FROM users; -- 只查询需要的列(推荐做法) SELECT user_id, username, email, created_at FROM users; -- 给列起别名(让结果更易读) SELECT user_id AS '用户ID', username AS '用户名', created_at AS '注册时间' FROM users;

🔑 关键点:

SELECT *虽然方便,但在生产环境中要避免——不知道表有多少列,容易查出大量不需要的数据

AS起别名,让输出结果更直观,也方便后续引用


二、WHERE:精准筛选你要的行

WHERE 是 SQL 里用得最多的条件语句,几乎每个查询都需要它。

-- 精确匹配 SELECT * FROM orders WHERE status = 'paid'; -- 数值范围 SELECT * FROM orders WHERE amount > 100; -- 多条件:AND(都满足)/ OR(满足一个即可) SELECT * FROM orders WHERE status = 'paid' AND amount > 100; -- IN:匹配多个值(替代多个 OR) SELECT * FROM users WHERE city IN ('北京', '上海', '广州'); -- BETWEEN:范围查询(含两端) SELECT * FROM orders WHERE created_at BETWEEN '2026-01-01' AND '2026-03-31'; -- LIKE:模糊查询 -- % 代表任意多个字符,_ 代表一个字符 SELECT * FROM users WHERE username LIKE '张%'; -- 以"张"开头 SELECT * FROM users WHERE email LIKE '%@gmail%'; -- 包含 @gmail -- IS NULL / IS NOT NULL:处理空值 SELECT * FROM users WHERE phone IS NULL; -- 未填手机号的用户

🔑 关键点:

① NULL 不能用= NULL查,必须用IS NULL

② LIKE 查询在数据量大时很慢,如果要高性能搜索,考虑全文索引或搜索引擎

③ BETWEEN 包含两端值,相当于>= 左边 AND <= 右边


三、ORDER BY + LIMIT:排序和分页

取"TOP N"数据是数据分析的日常需求,ORDER BY + LIMIT 搞定它。

-- 按金额降序排列,取前10名 SELECT order_id, user_id, amount FROM orders ORDER BY amount DESC -- DESC 降序,ASC 升序(默认) LIMIT 10; -- 分页查询:取第2页,每页20条 -- LIMIT offset, count SELECT * FROM users ORDER BY created_at DESC LIMIT 20 OFFSET 20; -- 跳过前20条,取20条 -- 多列排序:先按城市,再按注册时间倒序 SELECT user_id, username, city, created_at FROM users ORDER BY city ASC, created_at DESC;

🔑 关键点:

LIMIT N OFFSET M=LIMIT M, N,两种写法等价

② 深分页(OFFSET 很大时)性能很差,实际业务中用"游标分页"代替


四、GROUP BY + 聚合函数:统计汇总的核心

数据分析最常见的需求:按维度统计数量、金额、均值。

-- 5个最常用的聚合函数 SELECT COUNT(*) AS 总记录数, -- 计数(包含NULL) COUNT(phone) AS 填了手机号, -- 计数(不含NULL) SUM(amount) AS 总金额, AVG(amount) AS 平均金额, MAX(amount) AS 最大金额, MIN(amount) AS 最小金额 FROM orders; -- GROUP BY:按维度分组汇总 -- 统计每个城市的用户数量 SELECT city, COUNT(*) AS user_count FROM users GROUP BY city ORDER BY user_count DESC; -- 多维度分组:按城市+性别统计 SELECT city, gender, COUNT(*) AS user_count, AVG(age) AS avg_age FROM users GROUP BY city, gender; -- HAVING:对分组结果再过滤(区别于 WHERE) -- 找出用户数超过1000的城市 SELECT city, COUNT(*) AS user_count FROM users GROUP BY city HAVING user_count > 1000 -- HAVING 过滤分组后的结果 ORDER BY user_count DESC;

🔑 关键点(容易混淆的地方):

WHERE在分组前过滤行,HAVING在分组后过滤组

SELECT里的列,要么是 GROUP BY 的分组列,要么是聚合函数的结果

COUNT(*)计所有行,COUNT(列名)不计 NULL 值

执行顺序口诀:

FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

五、JOIN:多表关联,这是SQL的灵魂

实际业务数据分散在多张表,JOIN 把它们拼起来。

-- 示例表结构: -- users(user_id, username, city) -- orders(order_id, user_id, amount, status) -- INNER JOIN(内连接):只保留两表都有的记录 -- 查询有下单记录的用户信息 SELECT u.username, u.city, o.order_id, o.amount FROM users u INNER JOIN orders o ON u.user_id = o.user_id; -- LEFT JOIN(左连接):保留左表全部记录,右表没匹配则NULL -- 查询所有用户,无论他们是否下过单 SELECT u.username, u.city, COUNT(o.order_id) AS order_count, -- 未下单用户结果为0 COALESCE(SUM(o.amount), 0) AS total_amount FROM users u LEFT JOIN orders o ON u.user_id = o.user_id GROUP BY u.user_id, u.username, u.city; -- 找出从未下单的用户(LEFT JOIN + IS NULL 技巧) SELECT u.user_id, u.username FROM users u LEFT JOIN orders o ON u.user_id = o.user_id WHERE o.order_id IS NULL; -- 右表没匹配到

JOIN 类型速记:

INNER JOIN:取交集,两边都有才出现

LEFT JOIN:左表全保留,右表没有填NULL(最常用)

RIGHT JOIN:右表全保留(可用 LEFT JOIN 反写代替,不推荐)

FULL OUTER JOIN:取并集(MySQL不支持,PostgreSQL支持)


六、子查询:把一个查询的结果当条件用

子查询相当于先执行括号里的查询,再把结果用在外层查询里。

-- 查询消费金额高于平均值的订单 SELECT order_id, user_id, amount FROM orders WHERE amount > ( SELECT AVG(amount) FROM orders -- 先算平均值 ); -- IN 子查询:查询购买过特定商品的用户 SELECT username FROM users WHERE user_id IN ( SELECT DISTINCT user_id FROM orders WHERE product_id = 1001 ); -- EXISTS:更高效的存在性判断 SELECT u.username FROM users u WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.user_id AND o.amount > 500 );

🔑 关键点:

① 子查询可以放在 WHERE/FROM/SELECT 后面

EXISTSIN在大数据量时性能更好(找到一条就停)

③ 嵌套超过3层的子查询建议改写为 JOIN 或 CTE(更易读)


七、CASE WHEN:SQL里的"if-else"

数据分层、标签打码、指标计算,都用它。

-- 基础用法:给用户打标签 SELECT user_id, amount, CASE WHEN amount >= 1000 THEN '高价值' WHEN amount >= 500 THEN '中价值' WHEN amount >= 100 THEN '低价值' ELSE '零星用户' END AS user_tier -- 给结果列起名 FROM orders; -- 实战:统计各价值层用户数量 SELECT user_tier, COUNT(*) AS user_count FROM ( SELECT user_id, CASE WHEN SUM(amount) >= 1000 THEN '高价值' WHEN SUM(amount) >= 500 THEN '中价值' ELSE '低价值' END AS user_tier FROM orders GROUP BY user_id ) AS t GROUP BY user_tier; -- CASE WHEN 做透视(行转列) -- 统计各城市不同订单状态的数量 SELECT city, COUNT(CASE WHEN o.status = 'paid' THEN 1 END) AS 已支付, COUNT(CASE WHEN o.status = 'pending' THEN 1 END) AS 待支付, COUNT(CASE WHEN o.status = 'refunded' THEN 1 END) AS 已退款 FROM users u LEFT JOIN orders o ON u.user_id = o.user_id GROUP BY city;

八、日期函数:处理时间数据必备

业务分析离不开日期维度,日期函数是数据分析师的标配。

-- 常用日期函数(MySQL) -- 获取当前时间 SELECT NOW(); -- 2026-04-26 10:00:00 SELECT CURDATE(); -- 2026-04-26 SELECT DATE(NOW()); -- 2026-04-26(从datetime取日期部分) -- 提取日期组成部分 SELECT YEAR(created_at) AS 年, MONTH(created_at) AS 月, DAY(created_at) AS 日, WEEKDAY(created_at) AS 周几, -- 0=周一,6=周日 HOUR(created_at) AS 小时 FROM orders; -- 日期计算 SELECT created_at, DATE_ADD(created_at, INTERVAL 7 DAY) AS 到期时间, -- 加7天 DATEDIFF(NOW(), created_at) AS 已经过天数 -- 日期差 FROM orders; -- 实战:统计近30天每日下单量 SELECT DATE(created_at) AS 日期, COUNT(*) AS 订单数, SUM(amount) AS 总金额 FROM orders WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY DATE(created_at) ORDER BY 日期;

九、字符串函数:清洗和处理文本数据

真实数据往往有各种"脏"情况,字符串函数帮你清洗。

-- 常用字符串函数 SELECT CONCAT(first_name, ' ', last_name) AS 全名, -- 拼接 LENGTH('你好世界'), -- 字节长度(汉字通常3字节) CHAR_LENGTH('你好世界'), -- 字符长度(=4) UPPER('hello'), -- 转大写 LOWER('HELLO'), -- 转小写 TRIM(' 船长 '), -- 去首尾空格 SUBSTRING('CaptainTalk', 1, 7) AS 截取, -- 截取字符串(从1开始) REPLACE('hello world', 'world', 'captain') AS 替换; -- 实战:从邮箱提取域名 SELECT email, SUBSTRING_INDEX(email, '@', -1) AS email_domain -- '@'后面的部分 FROM users; -- 判断是否包含特定关键词 SELECT * FROM articles WHERE INSTR(title, 'SQL') > 0; -- 比 LIKE 效率略高

十、WITH(CTE):让复杂查询变得可读

CTE(Common Table Expression)是现代SQL写法的标配,让多步骤查询清晰可维护。

-- 语法:WITH 临时结果集名 AS (子查询) -- 场景:计算用户的下单频次、总金额,找出高价值用户 WITH user_stats AS ( -- 第一步:汇总每个用户的数据 SELECT user_id, COUNT(*) AS order_count, SUM(amount) AS total_amount, AVG(amount) AS avg_amount, MAX(created_at) AS last_order_at FROM orders GROUP BY user_id ), user_tier AS ( -- 第二步:给用户打标签(引用上一步的CTE) SELECT user_id, order_count, total_amount, CASE WHEN total_amount >= 5000 THEN 'VIP' WHEN total_amount >= 1000 THEN '活跃' ELSE '普通' END AS tier FROM user_stats ) -- 第三步:关联用户信息,输出最终结果 SELECT u.username, u.city, t.order_count, t.total_amount, t.tier FROM users u JOIN user_tier t ON u.user_id = t.user_id WHERE t.tier = 'VIP' ORDER BY t.total_amount DESC;

🔑 为什么推荐 CTE?

① 比嵌套子查询更易读——每步有名字,逻辑清晰

② 可以被后续的 CTE 多次引用

③ 方便调试——可以单独运行每个 CTE 检查中间结果


汇总:10类语句速查表

| 语句 | 用途 | 关键点 |

|------|------|--------|

| SELECT/FROM | 取列 | 避免 SELECT * |

| WHERE | 筛选行 | NULL 用 IS NULL |

| ORDER BY + LIMIT | 排序分页 | 深分页用游标 |

| GROUP BY + 聚合 | 统计汇总 | HAVING 过滤分组 |

| JOIN | 多表关联 | LEFT JOIN 最常用 |

| 子查询 | 嵌套查询 | EXISTS > IN(大数据) |

| CASE WHEN | 条件分支 | 行转列神器 |

| 日期函数 | 时间处理 | 近N天用 DATE_SUB |

| 字符串函数 | 文本清洗 | TRIM 去空格 |

| CTE(WITH) | 复杂查询 | 替代嵌套子查询 |


写在最后

SQL 是数据分析师的"母语"。这10类语句,覆盖了80%的日常查询场景。

建议的学习路径:

① 先把 SELECT + WHERE + GROUP BY 练熟,能独立查单表数据

② 再学 JOIN,能把2-3张表关联起来分析

③ 最后学 CTE + 子查询,能处理复杂的多步骤业务问题

不要一上来就背函数,建好一张练习用的表,把本文的代码全部跑一遍,比看10遍文章管用。

后续我会继续写 SQL 进阶系列:JOIN 的7种用法、窗口函数实战、SQL 性能优化。

关注船长,数据分析师的进阶路不迷路。

本文作者:CaptainTalk | 数据分析 + 职场真相 + 投资洞察

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询