每天一句SQL是一种被低估的数据库能力提升方式。它不要求大块时间,而是用碎片时段消化一条有代表性的语句,逐步覆盖过滤、联结、聚合与窗口计算等核心语法。下面先给出整体练习路径,再逐类拆解例句。

一、单表过滤与聚合基础
初学者应从单表查询起步,重点理解WHERE在分组前过滤、HAVING在分组后过滤的差异。很多人在写统计类语句时,误把聚合前的条件放进HAVING,导致全表先聚合再判断,性能极差。
下面这句适合作为第一天练习:统计订单表中金额大于一百且状态正常的用户数。它同时涉及数值比较与计数去重,能让人直观感受条件位置的影响。
-- 查询消费次数超过3次的高价值用户数量 SELECT COUNT(DISTINCT user_id) AS vip_user_cnt FROM orders WHERE amount > 100 AND status = 'normal' AND create_time >= '2023-01-01';
该语句中WHERE先筛掉低效记录,再对user_id去重计数。若改写成HAVING amount > 100,数据库不得不先对所有订单分组求和,资源消耗成倍增加。每日体会这种细节,执行计划意识会自然建立。
二、多表联结与空值陷阱
第二阶段建议练习LEFT JOIN与NULL处理。业务报表常需保留主表全部记录,此时左联结不可或缺,但右表无匹配时产生的NULL容易让后续计算出错。
例如统计每个用户的最后登录时间,部分新用户尚无登录记录,若直接取MAX时间会得到NULL,前端展示可能异常。用COALESCE转成默认值是实用技巧。
-- 左联结获取用户及其最近登录时间,无登录则显示'1970-01-01'
SELECT u.user_id,
COALESCE(MAX(l.login_time), '1970-01-01') AS last_login
FROM users u
LEFT JOIN user_login l ON u.user_id = l.user_id
GROUP BY u.user_id;
这里LEFT JOIN保证用户表完整,COALESCE把NULL映射为可读默认值。每天写一句类似联结,能熟悉驱动表选择逻辑,也避免报表缺行。注意ON后条件与WHERE后条件的语义区别:放在ON里不影响主表保留,放在WHERE里可能把左联结变成内联结效果。
三、窗口函数每日进阶
当基础语法熟练后,窗口函数是最值得每天啃一句的难点。它在不破坏行数前提下完成分组排序与累计,比子查询更清晰。ROW_NUMBER、SUM OVER等都很适合拆开练。
比如找出每个部门薪资最高的前两人。用GROUP BY只能得极值,无法保留同行其他字段,窗口函数则轻松解决。下面例句演示了PARTITION BY与ORDER BY的配合。
-- 每个部门按薪资倒序排名,取前两名
SELECT dept_id, emp_name, salary, rnk
FROM (
SELECT dept_id,
emp_name,
salary,
ROW_NUMBER() OVER (
PARTITION BY dept_id
ORDER BY salary DESC
) AS rnk
FROM employee
) t
WHERE rnk <= 2;
子查询先算排名,外层再过滤。每日琢磨一个窗口函数用例,很快能替代繁琐的自关联。要注意ROW_NUMBER、RANK、DENSE_RANK的并列处理差异,这也是面试常问点。坚持每天一句SQL,三个月后复杂报表需求不再令人头疼。
四、如何设计自己的每日一句
除了跟练现成例句,更应学会从工作痛点提炼。比如某天线上慢查询因缺少索引导致LIKE全表扫,就可写一句带前缀匹配的查询并对比执行计划。这种 contextual 练习记忆最深。
建议准备一个文本文件,按日期追加语句与一句心得。周末回看能发现薄弱点。配合EXPLAIN观察扫描行数,比单纯背语法更有效。久而久之,看到业务描述就能在脑中映射出大致SQL骨架。
-- 用EXPLAIN观察查询代价(示例) EXPLAIN SELECT * FROM product WHERE category_id = 5 AND name LIKE '手机%';
上面这句能让人明白前缀LIKE可命中category_id与name的联合索引,而后缀LIKE则不行。每天积累这种实战认知,数据库思维自然成型。无需报班,靠每日一句足矣。