3. SQL 基础回顾:SELECT、WHERE、JOIN、GROUP BY、HAVING、ORDER BY、窗口函数基础

在信用评分模型的特征工程中,SQL 是提取、清洗和聚合数据的核心工具。本章将系统回顾 SQL 的六大基础子句及窗口函数,并结合信用评分场景说明其应用要点。

3.1 核心子句速览

子句 作用 信用评分典型场景
SELECT 指定查询列与表达式 选取客户ID、逾期天数、授信额度
WHERE 行级过滤 筛选近3个月有交易记录的客户
JOIN 关联多表 将客户主表与还款计划表、催收记录表关联
GROUP BY 分组聚合 按客户ID计算总借款笔数、平均逾期天数
HAVING 分组后过滤 筛选逾期次数 ≥ 3 的客户群
ORDER BY 排序 按风险评分降序排列输出
窗口函数 不改变行数的分析计算 计算客户历史还款的滚动逾期率
信用评分提示: 特征提取时,WHERE 过滤条件应优先于 JOIN 执行,可大幅减少中间数据量。建议在 ON 子句中使用索引字段,避免全表扫描。

3.2 SELECT 与 WHERE:精准定位风险样本

SELECT 用于定义输出字段,WHERE 用于行级过滤。在信用评分中,通常先通过 WHERE 缩小分析范围,再提取特征。

-- 提取近6个月有逾期记录的客户ID及最大逾期天数
SELECT 
    customer_id,
    MAX(dpd_days) AS max_dpd
FROM repayment_history
WHERE 
    record_date >= DATEADD(MONTH, -6, GETDATE())
    AND dpd_days > 0
GROUP BY customer_id;
优化技巧: 在 WHERE 条件列上建立复合索引(如 record_date, dpd_days),可显著提升过滤速度。避免在 WHERE 中对索引列使用函数,如 WHERE YEAR(record_date) = 2024 会失效,应改为 WHERE record_date >= '2024-01-01' AND record_date < '2025-01-01'。

3.3 JOIN:多表特征关联

信用评分模型通常需要整合客户基本信息表、交易流水表、还款计划表、外部征信表等。JOIN 是连接这些表的桥梁。

-- 关联客户主表与最近3个月交易汇总
SELECT 
    c.customer_id,
    c.credit_score,
    t.total_trans_amount,
    t.trans_count
FROM customer_master c
LEFT JOIN (
    SELECT 
        customer_id,
        SUM(amount) AS total_trans_amount,
        COUNT(*) AS trans_count
    FROM transaction_log
    WHERE trans_date >= DATEADD(MONTH, -3, GETDATE())
    GROUP BY customer_id
) t ON c.customer_id = t.customer_id;
常见陷阱: 使用 LEFT JOIN 时,若右表存在重复记录,会导致左表数据膨胀。建议先对右表做 GROUP BY 去重,或使用 DISTINCT 确保关联键唯一。

3.4 GROUP BY 与 HAVING:聚合特征与风险过滤

GROUP BY 将数据按客户分组,计算聚合指标(如总借款额、平均逾期天数、最大负债率)。HAVING 在聚合后过滤高风险群体。

-- 提取高风险客户:总借款超过50万且平均逾期天数 > 30
SELECT 
    customer_id,
    SUM(loan_amount) AS total_loan,
    AVG(dpd_days) AS avg_dpd
FROM loan_records
GROUP BY customer_id
HAVING 
    SUM(loan_amount) > 500000
    AND AVG(dpd_days) > 30;
性能要点: HAVING 在聚合后过滤,WHERE 在聚合前过滤。应尽量将能提前过滤的条件写在 WHERE 中,减少 GROUP BY 处理的数据量。

3.5 ORDER BY:排序输出

ORDER BY 用于对最终结果排序。在信用评分中,常用于按风险等级或评分值排序,便于人工审核。

-- 按风险评分升序排列,输出前100名高风险客户
SELECT 
    customer_id,
    risk_score
FROM customer_risk
ORDER BY risk_score ASC
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY;

3.6 窗口函数基础:滚动特征与排名

窗口函数在不减少行数的情况下,为每一行计算基于分组或排序的分析值。在信用评分中,窗口函数常用于计算滚动逾期率、历史最大负债、客户行为排名等。

-- 计算每个客户按时间排序的滚动平均逾期天数(前3笔)
SELECT 
    customer_id,
    record_date,
    dpd_days,
    AVG(dpd_days) OVER (
        PARTITION BY customer_id 
        ORDER BY record_date 
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS rolling_avg_dpd
FROM repayment_history;
窗口函数 vs GROUP BY: GROUP BY 会压缩行数,窗口函数保留所有行。在特征提取中,窗口函数适合生成“历史趋势”类特征,如近3次还款行为变化、最大连续逾期次数等。

3.7 SQL 子句执行顺序与优化

理解 SQL 子句的逻辑执行顺序,有助于写出高效的信用评分特征提取脚本。

SQL 子句逻辑执行顺序 1. FROM / JOIN 2. WHERE 3. GROUP BY 4. HAVING 5. SELECT 6. ORDER BY 优化要点 • WHERE 过滤优先于聚合 • HAVING 只放聚合后条件 • 窗口函数在 SELECT 阶段 执行,不影响行数 • ORDER BY 最后执行, 尽量配合 LIMIT 使用 • 子查询在 FROM 阶段 先物化,注意性能 • 索引利用:WHERE 列、 JOIN 列、ORDER BY 列 • 避免 SELECT *, 只取需要的字段

3.8 信用评分特征提取中的子句组合示例

以下示例展示如何组合多个子句,提取用于信用评分模型的关键特征。

-- 提取客户级特征:近12个月行为汇总
SELECT 
    c.customer_id,
    c.age,
    c.income_level,
    COALESCE(SUM(l.loan_amount), 0) AS total_loan_12m,
    COALESCE(AVG(l.dpd_days), 0) AS avg_dpd_12m,
    MAX(l.dpd_days) AS max_dpd_12m,
    COUNT(l.loan_id) AS loan_count_12m,
    -- 窗口函数:最近一次逾期天数
    LAST_VALUE(l.dpd_days) OVER (
        PARTITION BY c.customer_id 
        ORDER BY l.loan_date 
        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    ) AS last_dpd
FROM customer_master c
LEFT JOIN loan_records l 
    ON c.customer_id = l.customer_id
    AND l.loan_date >= DATEADD(YEAR, -1, GETDATE())
WHERE c.is_active = 1
GROUP BY 
    c.customer_id, c.age, c.income_level, l.loan_date, l.dpd_days
HAVING COUNT(l.loan_id) >= 1
ORDER BY total_loan_12m DESC;
关键提醒: 窗口函数与 GROUP BY 同时使用时,窗口函数在 GROUP BY 之后、ORDER BY 之前执行。若窗口函数引用了非分组列,需确保逻辑正确,或考虑使用子查询分离聚合与窗口计算。