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

MySQL中的公用表表达式CTE实战案例应用

很多同学不会使用MySQL中的公用表表达式,今天这篇文章详细为大家介绍一下。

基础概念:
公用表表达式:MySQL中的公用表表达式(Common Table Expressions,简称CTE)是一种临时的结果集,它可以在一个SELECT、INSERT、UPDATE或DELETE语句中被引用多次。CTE可以使得复杂的查询更加清晰和易于理解,因为它允许将查询分解为多个简单的部分。

实战案例:

先模拟点表和数据,数据大家可以自己造,以下只是方便为大家讲解,随机造的数据:

1. 创建表结构和数据

-- 创建员工表
CREATE TABLE employees (employee_id INT PRIMARY KEY,name VARCHAR(100),department_id INT,salary DECIMAL(10, 2),manager_id INT,hire_date DATE
);-- 创建部门表
CREATE TABLE departments (department_id INT PRIMARY KEY,department_name VARCHAR(100),location VARCHAR(100)
);-- 创建订单表
CREATE TABLE orders (order_id INT PRIMARY KEY,customer_id INT,order_date DATE,total_amount DECIMAL(10, 2)
);-- 创建订单详情表
CREATE TABLE order_details (order_detail_id INT PRIMARY KEY,order_id INT,product_id INT,quantity INT,price DECIMAL(10, 2)
);-- 创建产品表
CREATE TABLE products (product_id INT PRIMARY KEY,product_name VARCHAR(100),category_id INT,unit_price DECIMAL(10, 2)
);-- 创建客户表
CREATE TABLE customers (customer_id INT PRIMARY KEY,customer_name VARCHAR(100),city VARCHAR(100),country VARCHAR(100)
);-- 插入部门数据
INSERT INTO departments VALUES
(1, '研发部', '北京'),
(2, '市场部', '上海'),
(3, '财务部', '广州'),
(4, '人力资源部', '深圳'),
(5, '销售部', '杭州');-- 插入员工数据
INSERT INTO employees VALUES
(1, '张三', 1, 15000.00, NULL, '2018-01-15'),
(2, '李四', 1, 12000.00, 1, '2019-03-20'),
(3, '王五', 2, 13000.00, 1, '2018-05-10'),
(4, '赵六', 2, 10000.00, 3, '2020-02-25'),
(5, '钱七', 3, 11000.00, 1, '2019-07-12'),
(6, '孙八', 3, 9500.00, 5, '2021-01-05'),
(7, '周九', 4, 12500.00, 1, '2018-11-30'),
(8, '吴十', 5, 14000.00, 1, '2019-04-18'),
(9, '郑十一', 5, 10500.00, 8, '2020-08-22'),
(10, '刘十二', 5, 9000.00, 8, '2021-03-15');-- 插入客户数据
INSERT INTO customers VALUES
(1, '阿里巴巴', '杭州', '中国'),
(2, '腾讯', '深圳', '中国'),
(3, '百度', '北京', '中国'),
(4, '京东', '北京', '中国'),
(5, '华为', '深圳', '中国'),
(6, 'Apple', '纽约', '美国'),
(7, 'Google', '旧金山', '美国'),
(8, 'Microsoft', '西雅图', '美国');-- 插入产品数据
INSERT INTO products VALUES
(1, '笔记本电脑', 1, 8999.00),
(2, '智能手机', 1, 4999.00),
(3, '平板电脑', 1, 3999.00),
(4, '办公桌', 2, 1200.00),
(5, '办公椅', 2, 800.00),
(6, '打印机', 3, 2500.00),
(7, '投影仪', 3, 5000.00),
(8, '复印机', 3, 12000.00);-- 插入订单数据
INSERT INTO orders VALUES
(1, 1, '2023-01-15', 26997.00),
(2, 2, '2023-02-20', 9998.00),
(3, 3, '2023-03-10', 7998.00),
(4, 4, '2023-04-05', 12000.00),
(5, 1, '2023-05-12', 8000.00),
(6, 5, '2023-06-18', 15000.00),
(7, 6, '2023-07-22', 7500.00),
(8, 7, '2023-08-30', 24000.00);-- 插入订单详情数据
INSERT INTO order_details VALUES
(1, 1, 1, 3, 8999.00),
(2, 2, 2, 2, 4999.00),
(3, 3, 3, 2, 3999.00),
(4, 4, 4, 10, 1200.00),
(5, 5, 5, 10, 800.00),
(6, 6, 1, 1, 8999.00),
(7, 6, 2, 1, 4999.00),
(8, 7, 6, 3, 2500.00),
(9, 8, 8, 2, 12000.00);

2. WITH查询案例

案例1: 查询每个部门的平均工资并与公司整体平均工资比较
WITH dept_avg_salary AS (SELECT d.department_id,d.department_name,AVG(e.salary) AS avg_salaryFROM departments dJOIN employees e ON d.department_id = e.department_idGROUP BY d.department_id, d.department_name
),
company_avg AS (SELECT AVG(salary) AS company_avg_salaryFROM employees
)
SELECT d.department_id,d.department_name,d.avg_salary,c.company_avg_salary,d.avg_salary - c.company_avg_salary AS salary_difference
FROM dept_avg_salary d
CROSS JOIN company_avg c
ORDER BY d.avg_salary DESC;

在这里插入图片描述

案例2: 找出每个部门薪资最高的员工
WITH ranked_employees AS (SELECT e.employee_id,e.name,e.salary,e.department_id,d.department_name,RANK() OVER (PARTITION BY e.department_id ORDER BY e.salary DESC) AS salary_rankFROM employees eJOIN departments d ON e.department_id = d.department_id
)
SELECT employee_id,name,department_name,salary
FROM ranked_employees
WHERE salary_rank = 1
ORDER BY department_id;

在这里插入图片描述

案例3: 递归查询员工上下级关系
WITH RECURSIVE employee_hierarchy AS (-- 基础查询:找出顶级管理者SELECT employee_id,name,manager_id,1 AS level,CAST(name AS CHAR(1000)) AS hierarchy_pathFROM employeesWHERE manager_id IS NULLUNION ALL-- 递归查询:找出所有下属SELECT e.employee_id,e.name,e.manager_id,eh.level + 1,CONCAT(eh.hierarchy_path, ' > ', e.name)FROM employees eJOIN employee_hierarchy eh ON e.manager_id = eh.employee_id
)
SELECT employee_id,name,manager_id,level,hierarchy_path
FROM employee_hierarchy
ORDER BY level, employee_id;

在这里插入图片描述

案例4: 计算各城市的销售额并排名
WITH city_sales AS (SELECT c.city,SUM(o.total_amount) AS total_salesFROM customers cJOIN orders o ON c.customer_id = o.customer_idGROUP BY c.city
),
ranked_cities AS (SELECT city,total_sales,RANK() OVER (ORDER BY total_sales DESC) AS sales_rankFROM city_sales
)
SELECT city,total_sales,sales_rank
FROM ranked_cities
ORDER BY sales_rank;

在这里插入图片描述

案例5: 查找热门产品(销售额前3的产品)
WITH product_sales AS (SELECT p.product_id,p.product_name,SUM(od.quantity * od.price) AS total_salesFROM products pJOIN order_details od ON p.product_id = od.product_idGROUP BY p.product_id, p.product_name
),
ranked_products AS (SELECT product_id,product_name,total_sales,RANK() OVER (ORDER BY total_sales DESC) AS sales_rankFROM product_sales
)
SELECT product_id,product_name,total_sales
FROM ranked_products
WHERE sales_rank <= 3
ORDER BY sales_rank;

在这里插入图片描述

案例6: 计算每个月的销售额及环比增长率
WITH monthly_sales AS (SELECT YEAR(order_date) AS year,MONTH(order_date) AS month,SUM(total_amount) AS monthly_salesFROM ordersGROUP BY YEAR(order_date), MONTH(order_date)
),
sales_growth AS (SELECT ms.year,ms.month,ms.monthly_sales,LAG(ms.monthly_sales) OVER (ORDER BY ms.year, ms.month) AS prev_month_salesFROM monthly_sales ms
)
SELECT year,month,monthly_sales,prev_month_sales,CASE WHEN prev_month_sales IS NULL THEN NULLELSE ROUND((monthly_sales - prev_month_sales) / prev_month_sales * 100, 2)END AS growth_rate_percentage
FROM sales_growth
ORDER BY year, month;

在这里插入图片描述

案例7: 查找重复购买的客户及其总消费额
WITH customer_order_count AS (SELECT customer_id,COUNT(*) AS order_count,SUM(total_amount) AS total_spentFROM ordersGROUP BY customer_idHAVING COUNT(*) > 1
)
SELECT c.customer_id,c.customer_name,c.city,c.country,coc.order_count,coc.total_spent
FROM customer_order_count coc
JOIN customers c ON coc.customer_id = c.customer_id
ORDER BY coc.total_spent DESC;
案例8: 各部门员工工资区间分布
WITH salary_ranges AS (SELECT department_id,COUNT(CASE WHEN salary < 10000 THEN 1 END) AS low_salary,COUNT(CASE WHEN salary >= 10000 AND salary < 13000 THEN 1 END) AS medium_salary,COUNT(CASE WHEN salary >= 13000 THEN 1 END) AS high_salary,COUNT(*) AS total_employeesFROM employeesGROUP BY department_id
)
SELECT d.department_id,d.department_name,sr.low_salary,ROUND(sr.low_salary / sr.total_employees * 100, 2) AS low_salary_percentage,sr.medium_salary,ROUND(sr.medium_salary / sr.total_employees * 100, 2) AS medium_salary_percentage,sr.high_salary,ROUND(sr.high_salary / sr.total_employees * 100, 2) AS high_salary_percentage,sr.total_employees
FROM salary_ranges sr
JOIN departments d ON sr.department_id = d.department_id
ORDER BY d.department_id;

在这里插入图片描述

案例9: 查找客户购买的不同产品种类及总金额
WITH customer_products AS (SELECT o.customer_id,COUNT(DISTINCT od.product_id) AS distinct_products,SUM(od.quantity * od.price) AS total_amountFROM orders oJOIN order_details od ON o.order_id = od.order_idGROUP BY o.customer_id
),
avg_products AS (SELECT AVG(distinct_products) AS avg_distinct_productsFROM customer_products
)
SELECT c.customer_id,c.customer_name,cp.distinct_products,cp.total_amount,CASE WHEN cp.distinct_products > ap.avg_distinct_products THEN '多样化消费'ELSE '专一消费'END AS customer_type
FROM customer_products cp
JOIN customers c ON cp.customer_id = c.customer_id
CROSS JOIN avg_products ap
ORDER BY cp.distinct_products DESC, cp.total_amount DESC;

在这里插入图片描述

案例10: 计算员工的入职年限并按部门统计
WITH employee_tenure AS (SELECT employee_id,name,department_id,TIMESTAMPDIFF(YEAR, hire_date, CURDATE()) AS years_of_serviceFROM employees
),
dept_tenure_stats AS (SELECT department_id,AVG(years_of_service) AS avg_tenure,MIN(years_of_service) AS min_tenure,MAX(years_of_service) AS max_tenureFROM employee_tenureGROUP BY department_id
)
SELECT d.department_id,d.department_name,ROUND(dts.avg_tenure, 1) AS avg_years_of_service,dts.min_tenure AS min_years_of_service,dts.max_tenure AS max_years_of_service,COUNT(e.employee_id) AS employee_count
FROM departments d
JOIN dept_tenure_stats dts ON d.department_id = dts.department_id
JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name, dts.avg_tenure, dts.min_tenure, dts.max_tenure
ORDER BY avg_years_of_service DESC;

在这里插入图片描述

需要注意的是,MySQL 5.7及以下版本不支持WITH RECURSIVE语法,只有MySQL 8.0及以上版本才支持完整的CTE功能,包括递归CTE。

相关文章:

  • 调度算法的学习
  • 【高中数学/指数/对数】同构六君子之 x/e^x/lnx组合曲线
  • Git_获取GitLab的token方法(访问令牌)
  • map 中key 是否可以放置的自定义的对象?
  • 【嵌入式系统设计师(软考中级)】第一章:计算机系统基础知识(上)
  • linux命令八
  • SparkSQL Join的源码分析
  • python自动化浏览器标签页的切换
  • 大模型——Crawl4AI 中的数据提取策略
  • 【FPGA基础学习】DDS信号发生器设计
  • AI图片生成器
  • AIP-235 批量方法:Delete
  • idea如何使用git
  • Maybe:打造个人财务管理的开源操作系统
  • SpringBoot-基础特性
  • 前端vue3 实现倒计时功能 组件
  • 重返JAVA之路——图书管理系统
  • B2B2C多用户商城平台 的两种创新玩法
  • 华熙生物亮相消博会,这次又带来了什么样的变化?
  • springboot项目添加定时任务,用sftp推送zip包到目标服务器
  • 从黄仁勋到美国消费者,都在“突围”
  • 大理州工业投资(集团)有限公司党委副书记、副总经理赵云接受审查调查
  • 东航推出“上博号”班机,上博设立“东航特展厅”
  • 2025年青年普法志愿者法治文化基层行活动启动
  • 美法官裁定谷歌非法垄断在线广告
  • 特朗普:“百分之百”相信能与欧盟达成贸易协议