MySQL中的WITH

在 MySQL 中,WITH 子句用于定义 公共表表达式(CTE, Common Table Expression)。它可以让你在查询中定义一个临时结果集,这个结果集可以被后续的 SELECTINSERTUPDATEDELETE 查询引用。


WITH 的语法

WITH cte_name (column1, column2, ...) AS (
    -- 子查询
    SELECT ...
)
SELECT ...
FROM cte_name;

关键点:

  1. CTE 名称cte_name 是临时表的名称,后续可以用作表名。
  2. 列名(可选):可以为 CTE 的列指定名称;如果不指定,将从子查询的列自动继承。
  3. 子查询WITH 中包含的子查询生成一个结果集,可以在主查询中多次引用。
  4. 多个 CTE:可以定义多个 CTE,用逗号分隔。

CTE 的特性与优点

  1. 提高代码可读性:将复杂查询拆分为多个步骤,每个 CTE 表示一个逻辑步骤。
  2. 避免重复代码:可在主查询中多次使用同一个 CTE,而不需要重复编写子查询。
  3. 简化维护:让 SQL 语句结构更加直观,便于维护。

示例

1. 简单的 CTE 示例

计算每个部门的平均工资,然后筛选工资高于一定标准的部门:

WITH DepartmentAvgSalary AS (
    SELECT 
        department_id, 
        AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT *
FROM DepartmentAvgSalary
WHERE avg_salary > 5000;

2. 多个 CTE 的使用

链式使用多个 CTE,计算部门平均工资,并统计高于某工资水平的员工数量:

WITH DepartmentAvgSalary AS (
    SELECT 
        department_id, 
        AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
),
HighPaidEmployees AS (
    SELECT 
        e.department_id, 
        COUNT(*) AS high_paid_count
    FROM employees e
    JOIN DepartmentAvgSalary d ON e.department_id = d.department_id
    WHERE e.salary > d.avg_salary
    GROUP BY e.department_id
)
SELECT 
    h.department_id, 
    d.avg_salary, 
    h.high_paid_count
FROM DepartmentAvgSalary d
JOIN HighPaidEmployees h ON d.department_id = h.department_id;

3. 递归 CTE

MySQL 支持递归 CTE,适合处理层级结构(如组织结构、文件系统)。

示例:计算员工的所有下属
WITH RECURSIVE EmployeeHierarchy AS (
    -- 基础情况:起点员工
    SELECT 
        employee_id, 
        manager_id, 
        1 AS level
    FROM employees
    WHERE manager_id IS NULL -- 顶级经理
    
    UNION ALL
    
    -- 递归情况:找到下属
    SELECT 
        e.employee_id, 
        e.manager_id, 
        eh.level + 1
    FROM employees e
    JOIN EmployeeHierarchy eh ON e.manager_id = eh.employee_id
)
SELECT *
FROM EmployeeHierarchy;

CTE 与子查询对比

特性 CTE 子查询
语义清晰度 语义清晰,可命名为逻辑步骤 嵌套查询语义较复杂
代码重用 可重用 不可重用
性能 MySQL 会优化部分 CTE 依赖查询上下文优化
递归支持 支持 不支持

使用注意事项

  1. 版本限制

    • MySQL 在 8.0 及以上版本支持 WITH
    • 如果使用旧版本,可以使用临时表或视图代替。
  2. 性能问题

    • CTE 是逻辑上的临时表,MySQL 在某些场景下会生成物化表,可能会导致性能问题。
    • 如果 CTE 被多次引用,MySQL 可能会多次执行 CTE。需要测试性能。
  3. 递归深度限制

    • MySQL 默认递归 CTE 的最大深度为 1000,可以通过 cte_max_recursion_depth 参数调整。

适用场景

  • 复杂查询拆解:将复杂的业务逻辑分解为多个步骤。
  • 递归查询:适合处理层次数据(如组织架构)。
  • 性能优化:减少冗余代码,提高可维护性。

通过灵活运用 WITH 子句,可以让 MySQL 查询既高效又易读。

你可能感兴趣的:(MySQL,mysql,数据库)