欢迎光临中国葬花网
详情描述

一、什么是CTE?

CTE(Common Table Expressions,公共表表达式)是MySQL 8.0引入的重要特性,它允许在查询中定义临时的命名结果集。

-- 基本语法
WITH cte_name [(column_list)] AS (
    SELECT ...
)
SELECT * FROM cte_name;

二、CTE的优势

1. 可读性更强

-- 传统方式:嵌套子查询
SELECT * FROM (
    SELECT * FROM employees WHERE salary > 5000
) AS high_salary_emp;

-- CTE方式:更清晰
WITH high_salary_emp AS (
    SELECT * FROM employees WHERE salary > 5000
)
SELECT * FROM high_salary_emp;

2. 支持递归查询

-- 查询组织结构树
WITH RECURSIVE org_tree AS (
    -- 初始查询:根节点
    SELECT 
        employee_id, 
        name, 
        manager_id,
        1 AS level
    FROM employees 
    WHERE manager_id IS NULL

    UNION ALL

    -- 递归查询:下级员工
    SELECT 
        e.employee_id, 
        e.name, 
        e.manager_id,
        ot.level + 1
    FROM employees e
    JOIN org_tree ot ON e.manager_id = ot.employee_id
)
SELECT * FROM org_tree ORDER BY level, employee_id;

三、CTE的使用模式

模式1:简单CTE(提高可读性)

-- 示例:计算部门平均工资
WITH dept_stats AS (
    SELECT 
        department_id,
        COUNT(*) AS emp_count,
        AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT 
    d.department_name,
    ds.emp_count,
    ds.avg_salary
FROM dept_stats ds
JOIN departments d ON ds.department_id = d.department_id
WHERE ds.avg_salary > 8000;

模式2:多个CTE(链式使用)

WITH 
sales_summary AS (
    SELECT 
        product_id,
        SUM(quantity) AS total_quantity,
        SUM(amount) AS total_amount
    FROM sales
    GROUP BY product_id
),
product_info AS (
    SELECT 
        p.product_id,
        p.product_name,
        p.category,
        s.total_quantity,
        s.total_amount
    FROM products p
    JOIN sales_summary s ON p.product_id = s.product_id
)
SELECT 
    category,
    SUM(total_quantity) AS cat_quantity,
    SUM(total_amount) AS cat_amount
FROM product_info
GROUP BY category
ORDER BY cat_amount DESC;

模式3:递归CTE(层级数据处理)

示例1:生成数字序列

-- 生成1到10的数字
WITH RECURSIVE numbers AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM numbers WHERE n < 10
)
SELECT * FROM numbers;

示例2:文件路径拆解

WITH RECURSIVE path_parts AS (
    SELECT 
        'a/b/c/d/e.txt' AS full_path,
        1 AS position,
        SUBSTRING_INDEX('a/b/c/d/e.txt', '/', 1) AS part,
        SUBSTRING('a/b/c/d/e.txt', LENGTH(SUBSTRING_INDEX('a/b/c/d/e.txt', '/', 1)) + 2) AS remainder

    UNION ALL

    SELECT 
        full_path,
        position + 1,
        CASE 
            WHEN LOCATE('/', remainder) > 0 
            THEN SUBSTRING_INDEX(remainder, '/', 1)
            ELSE remainder
        END,
        CASE 
            WHEN LOCATE('/', remainder) > 0 
            THEN SUBSTRING(remainder, LENGTH(SUBSTRING_INDEX(remainder, '/', 1)) + 2)
            ELSE ''
        END
    FROM path_parts
    WHERE remainder != ''
)
SELECT * FROM path_parts;

四、CTE的实用场景

场景1:数据清洗和转换

-- 数据清洗:处理缺失值
WITH cleaned_data AS (
    SELECT 
        customer_id,
        COALESCE(name, 'Unknown') AS customer_name,
        COALESCE(email, 'no-email@example.com') AS customer_email,
        CASE 
            WHEN age < 0 THEN NULL
            WHEN age > 120 THEN NULL
            ELSE age
        END AS valid_age
    FROM raw_customers
)
SELECT * FROM cleaned_data WHERE valid_age IS NOT NULL;

场景2:复杂分析查询

-- 计算员工排名和百分比
WITH employee_rank AS (
    SELECT 
        employee_id,
        name,
        salary,
        department_id,
        RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank,
        PERCENT_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) * 100 AS percentile
    FROM employees
)
SELECT 
    e.*,
    d.department_name
FROM employee_rank e
JOIN departments d ON e.department_id = d.department_id
WHERE e.dept_rank <= 3;

场景3:数据分页优化

-- 高效分页查询
WITH ranked_data AS (
    SELECT 
        *,
        ROW_NUMBER() OVER (ORDER BY create_time DESC) AS rn
    FROM large_table
    WHERE status = 'active'
)
SELECT * FROM ranked_data
WHERE rn BETWEEN 1001 AND 1100;

五、CTE性能优化技巧

1. 使用MATERIALIZED强制物化

-- MySQL 8.0.16+ 支持
WITH /*+ MATERIALIZED */ expensive_cte AS (
    SELECT * FROM large_table WHERE complex_condition
)
SELECT * FROM expensive_cte;

2. 避免无限递归

-- 设置递归深度限制
SET SESSION cte_max_recursion_depth = 1000;

WITH RECURSIVE cte AS (
    -- ...
)
SELECT * FROM cte;

3. 合理使用索引

-- 确保CTE查询能使用索引
WITH indexed_cte AS (
    SELECT * FROM orders 
    WHERE order_date >= '2024-01-01'
    -- 确保order_date有索引
)
SELECT * FROM indexed_cte;

六、CTE vs 临时表 vs 子查询

特性 CTE 临时表 子查询
生命周期 单次查询 会话级别 单次查询
性能 优化器可优化 需要手动优化 可能影响性能
可读性 中等
递归支持
复用性 查询内复用 会话内复用 单次使用

七、实战案例:电商数据分析

-- 分析用户购买行为
WITH 
user_orders AS (
    SELECT 
        user_id,
        COUNT(DISTINCT order_id) AS order_count,
        SUM(amount) AS total_spent,
        MIN(order_date) AS first_order_date,
        MAX(order_date) AS last_order_date
    FROM orders
    WHERE order_date >= DATE_SUB(NOW(), INTERVAL 90 DAY)
    GROUP BY user_id
),
user_segments AS (
    SELECT 
        user_id,
        order_count,
        total_spent,
        CASE 
            WHEN order_count >= 10 THEN 'VIP'
            WHEN order_count >= 5 THEN 'Regular'
            WHEN order_count >= 1 THEN 'Casual'
            ELSE 'Inactive'
        END AS user_segment,
        DATEDIFF(NOW(), last_order_date) AS days_since_last_order
    FROM user_orders
)
SELECT 
    user_segment,
    COUNT(*) AS user_count,
    AVG(order_count) AS avg_orders,
    AVG(total_spent) AS avg_spent,
    AVG(days_since_last_order) AS avg_inactive_days
FROM user_segments
GROUP BY user_segment
ORDER BY avg_spent DESC;

八、注意事项

版本要求:MySQL 8.0+ 递归限制:默认最大递归深度1000 性能考虑:复杂CTE可能不如临时表高效 可更新性:CTE通常是只读的

九、最佳实践

命名清晰:使用有意义的CTE名称 适当拆分:复杂的逻辑拆分成多个CTE 性能测试:对比CTE和传统方式的性能 文档注释:为复杂CTE添加注释 避免过深递归:控制递归深度

CTE是MySQL现代查询模式的重要部分,合理使用可以显著提高SQL的可读性和维护性,特别适合复杂的数据分析和报表查询场景。

相关帖子
qqprotect.exe是什么进程?qqprotect.exe怎么禁止自动启动?
qqprotect.exe是什么进程?qqprotect.exe怎么禁止自动启动?
2026年苏超联赛的欧战资格是如何分配和竞争的?
2026年苏超联赛的欧战资格是如何分配和竞争的?
民俗文化中的苋菜:端午节食用苋菜习俗的地域分布考
民俗文化中的苋菜:端午节食用苋菜习俗的地域分布考
透过后视镜看科技迭代:早期发明的“冷门遗珠”如何悄悄影响当下生活?
透过后视镜看科技迭代:早期发明的“冷门遗珠”如何悄悄影响当下生活?
山野中的映山红:解读杜鹃花在传统文化中的象征意义。
山野中的映山红:解读杜鹃花在传统文化中的象征意义。
白银市网站开发设计#erp系统开发,一站式服务
白银市网站开发设计#erp系统开发,一站式服务
在异地提交了换证申请后,因故需要取消或修改信息该如何操作?
在异地提交了换证申请后,因故需要取消或修改信息该如何操作?
山南市网站优化公司#精准获客助手,模板建站
山南市网站优化公司#精准获客助手,模板建站
农业遥感如何帮助农民了解作物长势并预估产量,2026年有哪些新应用?
农业遥感如何帮助农民了解作物长势并预估产量,2026年有哪些新应用?
在选择医保定点药店时,我们应该重点考虑和对比哪些因素?
在选择医保定点药店时,我们应该重点考虑和对比哪些因素?
为什么说智能水表和电表的数据,正在成为评估个人信用的潜在依据?
为什么说智能水表和电表的数据,正在成为评估个人信用的潜在依据?
南充市安卓系统app开发@品牌网站定制开发,专业建站
南充市安卓系统app开发@品牌网站定制开发,专业建站
恋爱期间共同出资买房但未结婚,房产的归属问题应该如何妥善处理?
恋爱期间共同出资买房但未结婚,房产的归属问题应该如何妥善处理?
如果未来想买下政府持有的产权份额,具体的评估和购买流程是怎样的?
如果未来想买下政府持有的产权份额,具体的评估和购买流程是怎样的?
在2026年,面对越来越逼真的AI生成内容,我们该如何保持警惕?
在2026年,面对越来越逼真的AI生成内容,我们该如何保持警惕?
员工主动辞职时,当年未休的年休假工资应该如何正确计算和支付?
员工主动辞职时,当年未休的年休假工资应该如何正确计算和支付?
2026年想将家里的高额宽带套餐降级,运营商却设置重重障碍该怎么办?
2026年想将家里的高额宽带套餐降级,运营商却设置重重障碍该怎么办?
汉中市正规殡葬公司|丧葬服务公司,搭设灵堂
汉中市正规殡葬公司|丧葬服务公司,搭设灵堂
在停工停课期间,企业是否有权安排员工使用带薪年假或其他假期?
在停工停课期间,企业是否有权安排员工使用带薪年假或其他假期?
延安市网站建设推广服务#外贸网站建设,高端网站开发设计
延安市网站建设推广服务#外贸网站建设,高端网站开发设计