📖 SQL魔法课堂:CTE

🎩 第一章:什么是CTE?

CTE(Common Table Expression) 就像 SQL 里的「临时笔记本」📒:

sql 复制代码
WITH 临时笔记本 AS (  
    SELECT ... FROM ...  -- 先写点笔记
)
SELECT * FROM 临时笔记本;  -- 再用笔记做分析
  • 特点

    • 📌 临时性:仅在当前查询有效(像一次性草稿纸)
    • 🧩 可复用:可在一个查询中多次引用
    • 🪄 自描述:增强SQL可读性(比子查询更清晰)

🌟 第二章:递归CTE------时间魔法师

当CTE学会「自我复制」,它就成了处理树形结构、日期序列的利器!

🔮 经典结构

sql 复制代码
SQL
WITH RECURSIVE 时间魔法师 AS (
    -- 🪄 初始咒语(锚点)
    SELECT 开始时间, 结束时间 FROM 时间表 WHERE...
    
    UNION ALL  -- 连接符
    
    -- 🔄 递归咒语(时间+1天)
    SELECT 开始时间, 结束时间 + 1天 
    FROM 时间魔法师 
    WHERE 结束时间 < 目标时间
)

举个栗子🌰

把「2025-03-10 到 2025-03-12」的假期拆分成三天:

sql 复制代码
SQL
WITH RECURSIVE 拆分假期 AS (
    SELECT '2025-03-10' AS 假期日, '2025-03-12' AS 结束日
    UNION ALL
    SELECT 假期日 + 1 DAY, 结束日 
    FROM 拆分假期 
    WHERE 假期日 < 结束日
)
SELECT * FROM 拆分假期;

输出结果

yaml 复制代码
TEXT
| 假期日      | 结束日      |
|------------|------------|
| 2025-03-10 | 2025-03-12 |
| 2025-03-11 | 2025-03-12 |
| 2025-03-12 | 2025-03-12 | 

🛠️ 第三章:CTE实战------假期拆分器

需求:把员工请假记录按天展开,并关联企业ID

sql 复制代码
SQL
WITH RECURSIVE 假期拆分器 AS (
    -- 🎯 锚点:获取原始请假单
    SELECT 
        vacation_id,
        emp_id,
        ent_id,
        DATE(start_time) AS 开始日,
        DATE(end_time) AS 结束日
    FROM vacation 
    WHERE emp_id = 1001
    
    UNION ALL
    
    -- ⏳ 递归:每天+1直到结束日
    SELECT 
        vacation_id,
        emp_id,
        ent_id,
        开始日 + INTERVAL 1 DAY,
        结束日
    FROM 假期拆分器
    WHERE 开始日 < 结束日
)
SELECT 
    ent_id,
    开始日 AS work_date,
    'holiday' AS type,
    vacation_id
FROM 假期拆分器
ORDER BY 开始日 DESC;

魔法效果

yaml 复制代码
TEXT
| ent_id | work_date   | type    | vacation_id |
|--------|-------------|---------|-------------|
| 1001   | 2025-03-12  | holiday | 202         |
| 1001   | 2025-03-11  | holiday | 202         |
| 1001   | 2025-03-10  | holiday | 202         |

⚠️ 第四章:避坑指南

  1. 严格模式咬人🐞

    • 错误1055 - Expression not in GROUP BY
    • 解法:GROUP BY 必须包含所有非聚合字段
    sql 复制代码
    SQL
    GROUP BY vacation_day, vacation_id, ent_id
  2. 递归深度限制

    • 默认最大递归100次,超长链需设置:
    sql 复制代码
    SQL
    SET @@cte_max_recursion_depth = 365;  -- 允许拆一年假期
  3. 性能优化

    • 📌 索引:vacation(emp_id, start_time, end_time)
    • 🚫 避免大表递归:超过1万行的递归可能变慢

💡 第五章:什么时候用CTE?

场景 优点 举个栗子
多层嵌套查询 代码更易读 🧐 报表统计中的多步骤计算
递归结构处理 轻松拆解树形数据 🌲 组织架构、日期序列
临时结果复用 避免重复计算 ⚡ 多个JOIN用同一子查询

✨ 总结:CTE的魔法三要素

  1. 清晰结构WITH CTE名称 AS (...) 像写大纲
  2. 递归力量UNION ALL + 终止条件 实现循环
  3. 严格模式生存法则:GROUP BY 要完整!
相关推荐
程序猿小D2 分钟前
Java项目:基于SSM框架实现的校园活动资讯网管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
java·数据库·mysql·spring·毕业设计·ssm框架·校园活动
__風__4 小时前
从本地 Docker 部署的 Dify 中导出知识库内容(1.6版本亲测有效)
人工智能·python·mysql·语言模型
Aeside14 小时前
从订单ID说起:揭秘MySQL索引结构 & 设计
mysql
知其然亦知其所以然5 小时前
MySQL社招面试题:索引有哪几种类型?我讲给你听的不只是答案!
后端·mysql·面试
Lx3526 小时前
子查询扁平化技巧:减少嵌套层级的查询重构
sql·mysql
神仙别闹6 小时前
基于JSP+MySQL 实现(Web)毕业设计题目收集系统
java·前端·mysql
正经教主6 小时前
【n8n】mysql凭证设置,及注意问题
数据库·mysql·n8n
江南时雨7 小时前
MySQL 中 CHAR 和 VARCHAR 类型有什么区别?
数据库·mysql
埃泽漫笔7 小时前
MySQL - 性能优化
mysql
hh真是个慢性子8 小时前
MySQL自动化安装工具-mysqldeploy
运维·数据库·mysql·golang·自动化