3. SQL 基础回顾:SELECT查询、WHERE条件过滤、聚合函数与GROUP BY分组
在实时交易风控巡检中,SQL 是提取、过滤、汇总交易数据的核心工具。本节将系统回顾四个最基础也最关键的 SQL 子句:SELECT、WHERE、聚合函数 与 GROUP BY。掌握这些语法,是后续构建告警阈值与稳定性分析的前提。
3.1 SELECT 查询:数据检索的起点
SELECT 用于指定要从表中检索哪些列。在风控场景中,通常需要从交易流水表(如 transactions)中提取交易 ID、金额、时间、商户号等字段。
基础语法:
SELECT column1, column2, ...
FROM table_name;
若要查询所有列,可使用 SELECT *,但在生产环境中应尽量避免,以减少 I/O 开销。
| 查询目标 | SQL 示例 | 说明 |
|---|---|---|
| 查询指定列 | SELECT trans_id, amount, trans_time FROM transactions; |
只返回交易ID、金额、时间三列 |
| 查询所有列 | SELECT * FROM transactions; |
返回所有字段,谨慎使用 |
| 使用别名 | SELECT amount AS 交易金额 FROM transactions; |
用 AS 为列起别名,增强可读性 |
3.2 WHERE 条件过滤:精准定位风险交易
WHERE 子句用于过滤记录,只返回满足条件的行。在风控巡检中,这是定位异常交易的核心手段。
风控常用过滤条件:
- 金额阈值:
WHERE amount > 10000(大额交易) - 时间范围:
WHERE trans_time >= '2025-01-01'(指定日期后) - 多条件组合:
WHERE status = '失败' AND retry_count > 3 - 范围查询:
WHERE amount BETWEEN 5000 AND 20000 - 集合匹配:
WHERE merchant_id IN ('M001', 'M045', 'M102')
-- 示例:查询过去1小时内金额超过5万元且状态为“成功”的交易
SELECT trans_id, amount, trans_time, merchant_id
FROM transactions
WHERE trans_time >= NOW() - INTERVAL '1 hour'
AND amount > 50000
AND status = 'success';
3.3 聚合函数:从明细到统计
聚合函数对一组值执行计算并返回单个值。在告警阈值分析中,聚合函数用于计算均值、总和、计数等统计量。
| 函数 | 作用 | 风控应用场景 |
|---|---|---|
COUNT(*) |
统计行数 | 统计某时段交易笔数 |
COUNT(DISTINCT col) |
统计不重复值的数量 | 统计不同商户数、不同IP数 |
SUM(col) |
求和 | 计算总交易金额 |
AVG(col) |
求平均值 | 计算平均交易金额 |
MAX(col) |
求最大值 | 找出单笔最大金额 |
MIN(col) |
求最小值 | 找出单笔最小金额 |
注意:聚合函数会忽略
NULL 值(COUNT(*) 除外,它统计所有行)。在计算平均值时,如果某行金额为 NULL,该行不会被计入分母。
3.4 GROUP BY 分组:按维度聚合
GROUP BY 将结果集按一个或多个列分组,然后对每个组应用聚合函数。这是风控巡检中按商户、渠道、时间窗口等维度进行统计的关键操作。
核心规则:
SELECT子句中出现的非聚合列,必须出现在GROUP BY中。WHERE在分组前过滤行,HAVING在分组后过滤组。
-- 示例:按商户分组,统计每个商户的交易笔数、总金额和平均金额
SELECT merchant_id,
COUNT(*) AS 交易笔数,
SUM(amount) AS 总金额,
AVG(amount) AS 平均金额
FROM transactions
WHERE trans_time >= '2025-06-01'
GROUP BY merchant_id
ORDER BY 总金额 DESC;
3.5 综合案例:实时风控巡检中的 SQL 组合
以下是一个贴近真实巡检场景的 SQL 示例,综合运用了本节所有知识点:
-- 巡检目标:按商户和小时统计交易量,识别异常激增
SELECT
merchant_id,
DATE_TRUNC('hour', trans_time) AS 交易小时,
COUNT(*) AS 交易笔数,
SUM(amount) AS 交易总金额,
AVG(amount) AS 平均金额,
MAX(amount) AS 最大单笔金额
FROM transactions
WHERE trans_time >= NOW() - INTERVAL '24 hours'
AND status = 'success'
GROUP BY merchant_id, DATE_TRUNC('hour', trans_time)
HAVING COUNT(*) > 100 -- 笔数超过100的时段
OR SUM(amount) > 500000 -- 或总金额超过50万
ORDER BY 交易小时 DESC, 交易总金额 DESC;
巡检要点:
- WHERE 先过滤出过去24小时的成功交易,减少计算量。
- GROUP BY 按商户和小时两个维度分组,实现细粒度监控。
- HAVING 在分组后筛选出笔数或金额异常的时段,直接定位风险窗口。
- ORDER BY 按时间倒序、金额降序排列,优先查看最新且金额最大的异常。
3.6 常见错误与避坑指南
| 错误类型 | 错误示例 | 正确写法 | 说明 |
|---|---|---|---|
| SELECT 列未在 GROUP BY 中 | SELECT merchant_id, amount, COUNT(*) FROM t GROUP BY merchant_id; |
SELECT merchant_id, SUM(amount), COUNT(*) FROM t GROUP BY merchant_id; |
amount 非聚合列且未出现在 GROUP BY 中,多数数据库会报错 |
| WHERE 中使用聚合函数 | WHERE COUNT(*) > 10 |
使用 HAVING COUNT(*) > 10 |
WHERE 在分组前执行,不能引用聚合结果 |
| COUNT(*) 与 COUNT(col) 混淆 | COUNT(amount) 期望统计所有行 |
明确需求:COUNT(*) 统计行数,COUNT(amount) 统计非 NULL 行数 |
若 amount 列存在 NULL,两者结果不同 |
| HAVING 与 WHERE 顺序颠倒 | GROUP BY ... HAVING ... WHERE ... |
WHERE ... GROUP BY ... HAVING ... |
SQL 执行顺序:WHERE → GROUP BY → HAVING |
性能提示:在实时风控巡检中,尽量在 WHERE 阶段过滤掉大量无关数据,减少 GROUP BY 的处理行数。对于亿级表,建议先按时间分区,再在 WHERE 中指定时间范围,避免全表扫描。