公用表表达式(CTE)详解:针对 MySQL 和 SQL Server 数据库

公用表表达式(CTE,Common Table Expressions)是一种在 SQL 中定义临时结果集的方法,该结果集在单个查询的执行过程中可以被引用。CTE 提高了查询的可读性和结构化,特别适用于复杂的子查询和递归查询。本文将详细介绍 CTE 的概念和用法,并分别针对 MySQL 和 SQL Server 数据库进行说明。

什么是公用表表达式(CTE)

CTE 是一个命名的临时结果集,它在查询的执行范围内有效。CTE 的定义在 WITH 子句中,紧随其后的是查询主体。CTE 分为两种类型:

  1. 非递归 CTE:用于定义一次性计算结果的临时表。
  2. 递归 CTE:用于处理递归查询,如处理层次结构数据(例如组织结构图)。

CTE 的语法

基本语法
sql 复制代码
WITH cte_name AS (
    SELECT column1, column2, ...
    FROM table_name
    WHERE condition
)
SELECT column1, column2, ...
FROM cte_name
WHERE condition;

MySQL 中的 CTE

MySQL 从 8.0 版本开始支持 CTE。下面是一些常见的使用场景。

示例 1:非递归 CTE

假设我们有一个名为 bs_bill_day 的表,并且希望使用 CTE 从该表中选择数据,然后限制结果为前 10 行。

sql 复制代码
WITH bill_cte AS (
    SELECT * FROM bs_bill_day
)
SELECT * 
FROM bill_cte 
LIMIT 10;
示例 2:递归 CTE

假设我们有一个表示员工和经理关系的表 employees,其中包含 employee_id 和 manager_id 列,我们希望找到某个经理及其所有下属。

sql 复制代码
WITH RECURSIVE employee_cte 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, ec.level + 1
    FROM employees e
    INNER JOIN employee_cte ec ON e.manager_id = ec.employee_id
)
SELECT * 
FROM employee_cte;

SQL Server 中的 CTE

SQL Server 从 2005 版本开始支持 CTE。它的语法和 MySQL 类似。

示例 1:非递归 CTE

假设我们有一个名为 bs_bill_day 的表,并且希望使用 CTE 从该表中选择数据,然后限制结果为前 10 行。

sql 复制代码
WITH bill_cte AS (
    SELECT * FROM bs_bill_day
)
SELECT TOP 10 * 
FROM bill_cte;
示例 2:递归 CTE

假设我们有一个表示员工和经理关系的表 employees,其中包含 employee_id 和 manager_id 列,我们希望找到某个经理及其所有下属。

sql 复制代码
WITH employee_cte 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, ec.level + 1
    FROM employees e
    INNER JOIN employee_cte ec ON e.manager_id = ec.employee_id
)
SELECT * 
FROM employee_cte;

使用 CTE 进行分页

在大数据集的分页查询中,CTE 也非常有用。以下是在 MySQL 和 SQL Server 中使用 CTE 进行分页的示例。

MySQL 分页
sql 复制代码
WITH bill_cte AS (
    SELECT * FROM bs_bill_day
)
SELECT * 
FROM bill_cte 
LIMIT 10 OFFSET 0; -- 获取第一页的10条记录

SQL Server 分页

sql 复制代码
WITH bill_cte AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY some_column) AS row_num
    FROM bs_bill_day
)
SELECT * 
FROM bill_cte
WHERE row_num BETWEEN 1 AND 10; -- 获取第一页的10条记录

mysql实现返回最近三十天的列

sql 复制代码
WITH RECURSIVE recent_day_cte AS (
    -- 初始查询,获取当前日期的订单记录
    SELECT CURDATE() AS dayKey

    UNION ALL

    -- 递归查询,获取前一天的订单记录
    SELECT DATE_SUB(dayKey, INTERVAL 1 DAY)
    FROM recent_day_cte
    WHERE dayKey >= CURDATE() - INTERVAL 29 DAY
)
SELECT *
FROM recent_day_cte;

sql server 实现返回最近三十天的列

sql 复制代码
WITH recent_dates_cte AS (
    -- 初始查询,获取当前日期的订单记录
    SELECT CAST(GETDATE() AS DATE) AS dayKey

    UNION ALL

    -- 递归查询,获取前一天的日期
    SELECT DATEADD(DAY, -1, dayKey)
    FROM recent_dates_cte
    WHERE dayKey >= DATEADD(DAY, -29, CAST(GETDATE() AS DATE))
)
SELECT *
FROM recent_dates_cte;

sql server 获取最近七个月的月份信息

sql 复制代码
WITH recent_dates_cte AS (
    -- 初始查询,获取当前日期的订单记录
    SELECT CAST(GETDATE() AS DATE) AS dayKey

    UNION ALL

    -- 递归查询,获取前一天的日期
    SELECT DATEADD(MONTH, -1, dayKey)
    FROM recent_dates_cte
    WHERE dayKey >= DATEADD(MONTH, -5, CAST(GETDATE() AS DATE))
),
month_key_cte as (
SELECT CONVERT(varchar(7),dayKey,120)  as monKey
FROM recent_dates_cte
)

select * from month_key_cte

sql server 获取最近七周的周信息

sql 复制代码
WITH recent_dates_cte AS (
    -- 初始查询,获取当前日期的订单记录
    SELECT CAST(GETDATE() AS DATE) AS dayKey

    UNION ALL

    -- 递归查询,获取前一天的日期
    SELECT DATEADD(WEEK, -1, dayKey)
    FROM recent_dates_cte
    WHERE dayKey >= DATEADD(WEEK, -5, CAST(GETDATE() AS DATE))
),
week_key_cte as (
    SELECT 
    CONCAT(DATEPART(YEAR, dayKey), '-', FORMAT(DATEPART(WEEK, dayKey), '00')) AS weekKey,
    CASE 
        WHEN DATEDIFF(WEEK, dayKey, GETDATE()) = 0 THEN '本周'
        WHEN DATEDIFF(WEEK, dayKey, GETDATE()) = 1 THEN '前1周'
        WHEN DATEDIFF(WEEK, dayKey, GETDATE()) = 2 THEN '前2周'
        WHEN DATEDIFF(WEEK, dayKey, GETDATE()) = 3 THEN '前3周'
        WHEN DATEDIFF(WEEK, dayKey, GETDATE()) = 4 THEN '前4周'
        WHEN DATEDIFF(WEEK, dayKey, GETDATE()) = 5 THEN '前5周'
        WHEN DATEDIFF(WEEK, dayKey, GETDATE()) = 6 THEN '前6周'
    END AS label
	FROM recent_dates_cte
)

select * from week_key_cte

有了这样的基础,实现最近6个月,最近5年,最近6周是不是特别简单了,方便统计,比如统计最近六周,半年,最近六年,有了with以后是不是好理解多了。

公用表表达式(CTE)是处理复杂查询的强大工具,提供了更好的代码可读性和结构化。在 MySQL 和 SQL Server 中使用 CTE,能够简化复杂的子查询,并且方便处理递归查询和分页查询。通过本文的介绍,希望读者能对 CTE 的概念和用法有更清晰的理解,并能在实际工作中应用这些技巧。

相关推荐
Decay__6 小时前
05_MySQL 常用 SQL 大全 —— 诊断、管理、优化辅助 SQL 与三大系统库速查
运维·数据库·sql·mysql·架构
小徐不徐说11 小时前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
论文复现现场11 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
Decay__12 小时前
04_MySQL DBA 日常运维手册 —— 会话管理、锁与阻塞、事务监控、慢查询与日志巡检
运维·数据库·sql·mysql·架构
心梦缘-雪雁13 小时前
SQL Server 查询数据存在哪个表里
数据库
lusklusklusk14 小时前
Python 巡检脚本:进程运行状态、数据库写入时效检查及邮件通知与告警
数据库·python·oracle
GeW15 小时前
产业新优势基础软件的人才底盘,从Linux与数据库开始
linux·数据库
SelectDB15 小时前
Doris Arrow Flight SQL 高速读取协议实战:与 Snowflake 客户端取数链路对照
大数据·数据库·数据分析
曼岛_15 小时前
[图解密码学]第4章 古典密码
java·数据库·密码学
瀚高PG实验室16 小时前
HGDB V9.0.5 .pgpass 免密登录提示 IsEncryptNon-base64 encoding 警告处理
数据库·postgresql·瀚高数据库