第1章 SQL基础查询与数据探索:SELECT、WHERE、GROUP BY 怎么用才算“懂”
做特征工程这么多年,我见过太多人上来就写复杂窗口函数、搞标签交叉。其实,变量衍生的第一步从来不是炫技,而是老老实实把原始数据摸清楚。SQL 基础查询就是那双“摸数据的手”。你想想看,连表里有几个重复值、分布长啥样都不清楚,后面的分箱、归一化不就成了瞎折腾?
这一章,咱们就先把 SELECT、WHERE、GROUP BY 这三板斧练扎实。我会用实际项目里踩过的坑来帮你避开弯路。
1.1 SELECT —— 你每天写的第一个单词,用对了吗?
SELECT 看起来简单,但“简单”往往最容易出问题。我记得有一次帮团队排查上游数据接口,对方说“字段我都取出来了呀”,结果一查,他用的是 SELECT * 硬拉了整张 200 列的表,下游 ETL 跑了一个半小时。所以说,SELECT 的核心原则是:只取你需要的。
- 取特定字段:
SELECT user_id, age, income—— 减少 IO,提升速度。 - 字段别名:
SELECT age AS 年龄—— 别笑,很多分析师不写别名,下游对接时一脸懵。 - 常量列与计算列:
SELECT 'v1.0' AS version, income / 12 AS monthly_income—— 变量衍生的起点。 - 去重:
SELECT DISTINCT user_id—— 检查唯一值数量,快速发现重复主键。
SELECT COUNT(*), COUNT(DISTINCT user_id) 看一眼。如果两个数不相等,说明这张表有重复记录,后面聚合前必须处理。
1.2 WHERE —— 让数据先“瘦身”,再干活
WHERE 不只是过滤条件那么简单。很多特征工程里,你需要在不同的子集上分别计算统计量,比如“高价值用户”和“普通用户”的消费均值差。这时候 WHERE 就是你的切割刀。
但注意:WHERE 的执行顺序在 GROUP BY 之前。这意味着你无法在 WHERE 里引用聚合后的结果。我刚开始做数据分析时就犯过这个错:
-- ❌ 错误写法:WHERE 不允许用聚合函数
SELECT user_id, SUM(amount) AS total
FROM orders
WHERE total > 1000 -- 这里会报错!
GROUP BY user_id;
正确的做法是用 HAVING 或在子查询里先聚合。不过这就是后面要讲的内容了。
这里列几个我常用的 WHERE 技巧:
| 场景 | 写法示例 | 注意 |
|---|---|---|
| 空值判断 | WHERE age IS NOT NULL | NULL 用 IS,不能用 = NULL |
| 日期范围 | WHERE create_date >= '2024-01-01' | 避免用函数包裹日期字段,会走不了索引 |
| 多条件组合 | WHERE status IN ('active','trial') AND plan_type = 'premium' | IN 里面不要放太多值,超过 1000 建议用临时表 |
WHERE LEFT(date_str,6) = '202401'……全表扫描了 20 分钟。如果源头没法改,至少自己先转成日期类型:SELECT TO_DATE('20240101','YYYYMMDD')。
1.3 GROUP BY —— 特征工程真正的“炼丹炉”
GROUP BY 是 SQL 里聚合能力最强的操作之一。你想啊,用户的历史订单总金额、平均消费间隔、购买品类数……这些最常用的统计特征,统统离不开 GROUP BY。在我的理解里,GROUP BY 就是把同类数据“压”成一个特征行的过程。
常见的聚合函数:
COUNT(*)/COUNT(DISTINCT column)—— 订单笔数、活跃天数SUM(column)—— 消费总额、停留时长AVG(column)—— 客单价、评分均值MAX(column)/MIN(column)—— 最早/最晚时间、极值偏差STDDEV(column)/VARIANCE(column)—— 波动性特征,比如价格标准差
但很多人忽略了多字段分组的威力。比如你想生成“每个用户在每个产品类别的平均消费”,就得写 GROUP BY user_id, category。这其实是特征交叉的一种原始形态。
SELECT user_id, COUNT(*) AS loan_cnt_3m
FROM loan_table
WHERE apply_date >= DATE_SUB('2024-12-01', INTERVAL 3 MONTH)
GROUP BY user_id;
注意:WHERE 一定要先过滤时间窗口,再 GROUP BY。如果先 GROUP BY 再过滤,大数据量下效率差 10 倍以上。
1.4 结合数据探索:SQL 给你的三把“探照灯”
写特征之前,我习惯先用 SQL 输出几个“探照灯”结果:
- 分布概览:对每个连续字段做
MIN, AVG, MAX, STDDEV—— 看看有没有异常值。 - 空值排查:
COUNT(*) - COUNT(age)算空值数量 —— 决定是填充还是删除。 - 分组对比:
GROUP BY label看正负样本在各维度的均值差异 —— 快速发现区分度高的特征。
你想想看,这三个步骤走完,你基本就清楚这张表里哪些字段“能用”,哪些“得洗”。后面的特征衍生才有方向。
知识结构梳理
下面这张图概括了本章的核心流程。从原始表到探索性输出,每一步都在为特征工程铺路:
这个流程你可能已经写过无数次了,但每一次 SELECT 之前,不妨先问自己:我到底需要哪些字段?过滤条件够严格吗?聚合后要不要再丢一次异常值?这些都是经验活,写多了自然就有肌肉记忆。