当前位置: 首页 > news >正文

CTE 的主要优势_以MySQL为例

CTE 的主要优势

1. 提高可读性和可维护性

优势说明:将复杂的查询分解成多个逻辑部分,每个部分都有一个有意义的名称。

传统子查询方式(难以阅读):

sql

SELECT *
FROM (SELECT customer_id, SUM(amount) as total_spentFROM orders WHERE order_date >= '2023-01-01'GROUP BY customer_id
) AS subquery
WHERE total_spent > 1000;

使用 CTE 方式(清晰易读):

sql

WITH customer_totals AS (SELECT customer_id, SUM(amount) as total_spentFROM orders WHERE order_date >= '2023-01-01'GROUP BY customer_id
)
SELECT *
FROM customer_totals
WHERE total_spent > 1000;

2. 避免重复代码

优势说明:当同一个子查询需要在多个地方使用时,CTE 只需定义一次,可多次引用。

示例

sql

WITH high_value_orders AS (SELECT * FROM orders WHERE amount > 1000
)
SELECT (SELECT COUNT(*) FROM high_value_orders) as total_count,(SELECT AVG(amount) FROM high_value_orders) as average_amount,hv.*
FROM high_value_orders hv
WHERE hv.customer_id IN (SELECT customer_id FROM high_value_orders GROUP BY customer_id HAVING COUNT(*) > 5
);

3. 支持递归查询

优势说明:CTE 支持递归,可以处理树形结构或层次化数据。

示例:查询组织架构中的所有下属

sql

WITH RECURSIVE org_chart AS (-- 锚点成员:找到指定员工SELECT employee_id, name, manager_id, 1 as levelFROM employeesWHERE employee_id = 101UNION ALL-- 递归成员:找到下属SELECT e.employee_id, e.name, e.manager_id, oc.level + 1FROM employees eINNER JOIN org_chart oc ON e.manager_id = oc.employee_id
)
SELECT * FROM org_chart;

4. 替代视图的临时使用

优势说明:当需要临时创建一个"视图"但不想永久保存在数据库中时,CTE 是完美选择。

示例

sql

-- 不需要创建永久视图,只需在查询中临时定义
WITH monthly_sales AS (SELECT YEAR(order_date) as year,MONTH(order_date) as month,SUM(amount) as total_sales,COUNT(*) as order_countFROM ordersGROUP BY YEAR(order_date), MONTH(order_date)
)
SELECT year, month,total_sales,order_count,total_sales / order_count as avg_order_value
FROM monthly_sales
ORDER BY year, month;

5. 简化复杂查询的调试过程

优势说明:可以逐步构建和测试复杂查询的各个部分。

示例:逐步构建销售分析报告

sql

-- 第一步:先测试基础CTE
WITH customer_orders AS (SELECT customer_id, COUNT(*) as order_count, SUM(amount) as total_spentFROM ordersGROUP BY customer_id
)
SELECT * FROM customer_orders; -- 先测试这部分-- 第二步:添加更多CTE和逻辑
WITH customer_orders AS (SELECT customer_id, COUNT(*) as order_count, SUM(amount) as total_spentFROM ordersGROUP BY customer_id
),
active_customers AS (SELECT * FROM customer_orders WHERE order_count >= 3
)
SELECT c.name,ac.order_count,ac.total_spent,ac.total_spent / ac.order_count as avg_order_value
FROM active_customers ac
JOIN customers c ON ac.customer_id = c.id;

6. 更好的性能优化(在某些情况下)

优势说明:MySQL 优化器有时可以更好地优化 CTE,尤其是当 CTE 被多次引用时。

示例

sql

WITH product_stats AS (SELECT product_id,AVG(quantity) as avg_quantity,MAX(price) as max_priceFROM order_detailsGROUP BY product_id
)
SELECT p.product_name,ps.avg_quantity,ps.max_price,(SELECT COUNT(*) FROM orders o JOIN order_details od ON o.order_id = od.order_id WHERE od.product_id = p.product_id) as total_orders
FROM products p
JOIN product_stats ps ON p.product_id = ps.product_id;

7. 支持多个 CTE 的链式使用

优势说明:可以在一个查询中定义多个 CTE,每个都可以基于前一个的结果。

示例

sql

WITH 
-- 第一个CTE:计算订单总数
order_counts AS (SELECT customer_id, COUNT(*) as total_ordersFROM ordersGROUP BY customer_id
),
-- 第二个CTE:筛选高价值客户
high_value_customers AS (SELECT customer_id, total_ordersFROM order_countsWHERE total_orders > 10
),
-- 第三个CTE:获取客户详情
customer_details AS (SELECT c.*, hvc.total_ordersFROM customers cJOIN high_value_customers hvc ON c.customer_id = hvc.customer_id
)
-- 主查询
SELECT customer_id,name,email,total_orders,CASE WHEN total_orders > 20 THEN '钻石客户'WHEN total_orders > 15 THEN '黄金客户'ELSE '白银客户'END as customer_level
FROM customer_details
ORDER BY total_orders DESC;

使用建议和注意事项

  1. 适度的使用:虽然 CTE 很强大,但不要过度使用。简单的查询不需要 CTE。
  2. 性能考虑:在某些情况下,CTE 可能不会比优化良好的子查询性能更好,需要实际测试。
  3. 递归深度限制:递归 CTE 有深度限制,可以通过 cte_max_recursion_depth 参数调整。
  4. 版本要求:确保你的 MySQL 版本支持 CTE(MySQL 8.0+ 完整支持)。
  5. 可读性与复杂度的平衡:虽然 CTE 提高了可读性,但过多的 CTE 也可能让查询变得复杂。

实际应用场景

  1. 报表生成:复杂的数据聚合和转换
  2. 数据清洗:多步骤的数据处理和转换
  3. 层次查询:组织架构、分类树、评论线程等
  4. 复杂业务逻辑:需要多步骤计算的业务场景
  5. 查询调试:逐步构建和测试复杂查询

CTE 是 SQL 开发中的强大工具,合理使用可以大大提高代码的质量和开发效率。

http://www.dtcms.com/a/358029.html

相关文章:

  • 函数返回对象时的临时对象与移动赋值探析——深入理解优化策略
  • Time-MOE添加MLP分类头进行分类任务
  • 智能消防栓闷盖终端:让城市消防管理更智慧高效
  • 开源 C++ QT Widget 开发(八)网络--Http文件下载
  • JavaScript 属性标识符详解
  • 197-200CSS3响应式布局,BFC
  • Ruoyi-vue-plus-5.x第一篇Sa-Token权限认证体系深度解析:1.4 Sa-Token高级特性实现
  • GitCode全方位解析:开源新星的崛起与极致实战指南
  • 从“互联网+”到“人工智能+”:云计算生态演进揭示AI应用破局之道
  • 【C++】第二十七节—C++11(下) | 可变参数模版+新的类功能+STL中一些变化+包装器
  • LeetCode54螺旋矩阵算法详解
  • 路径恢复回复给非常差
  • LeetCode 2540.最小公共值
  • Elasticsearch:Semantic text 字段类型
  • 【已解决】could not read Username for ‘https://x.x.x‘: No such device or address
  • 关于docker启动容器立即线下的错误解决
  • C++之stack类的代码及其逻辑详解
  • 3D生成模型-NeRF:用神经辐射场定义视图合成
  • MySQL數據庫開發教學(四) 後端與數據庫的交互
  • React Hooks深度解析与最佳实践:提升函数组件能力的终极指南
  • 科技信息差(8.30)
  • 聊一聊耳机串扰-Crosstalk
  • 知料觅得-新一代AI搜索引擎
  • RK3576开发板串口配置及使用
  • STM32 之GP2Y1014AU0F的应用--基于RTOS的环境
  • 在 Git Bash 中查看 Git 仓库远程地址
  • flink中 Lookup Join和Interval Join和Regular Join使用场景与对比
  • 【云原生】Docker 搭建Kafka服务两种方式实战操作详解
  • 阿里云如何申请免费的ssl证书并部署
  • 嵌入式Linux驱动开发:ICM20608六轴传感器SPI驱动