SQL进阶——with

在 MySQL 中,WITH 关键字用于定义 公用表表达式(Common Table Expressions,CTE)。CTE 是一个临时的结果集,可以在一个查询中多次引用,通常用于简化复杂查询,提高可读性。

基础语法

WITH cte_name AS (
    -- 子查询
    SELECT ...
)
SELECT ...
FROM cte_name;
  • cte_name 是 CTE 的名称。
  • WITH 子句中定义的 CTE 可以在后续的 SELECTINSERTUPDATEDELETE 语句中使用。

示例 1:简单的 CTE

假设有一个 employees 表,我们想查询工资高于平均工资的员工:

WITH avg_salary AS (
    SELECT AVG(salary) AS avg_sal FROM employees
)
SELECT name, salary
FROM employees, avg_salary
WHERE salary > avg_sal;
  • avg_salary 是一个 CTE,计算了员工的平均工资。
  • 在主查询中,我们将 employees 表与 avg_salary CTE 进行连接,筛选出工资高于平均工资的员工。

示例 2:递归 CTE

CTE 还支持递归查询,常用于处理层次结构数据(如树形结构)。

假设有一个 categories 表,存储了分类及其父分类:

CREATE TABLE categories (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    parent_id INT
);

我们想查询某个分类及其所有子分类:

WITH RECURSIVE category_tree AS (
    -- 基础查询:选择根节点
    SELECT id, name, parent_id
    FROM categories
    WHERE id = 1  -- 假设根节点的 id 是 1

    UNION ALL

    -- 递归查询:选择子节点
    SELECT c.id, c.name, c.parent_id
    FROM categories c
    INNER JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree;
  • WITH RECURSIVE 定义了一个递归 CTE。
  • 基础查询选择根节点。
  • 递归部分通过 UNION ALL 不断将子节点添加到结果集中,直到没有更多的子节点。

示例 3:多个 CTE

可以在一个查询中定义多个 CTE,用逗号分隔:

WITH
    dept_stats AS (
        SELECT department_id, AVG(salary) AS avg_sal
        FROM employees
        GROUP BY department_id
    ),
    high_paid_employees AS (
        SELECT e.name, e.salary, e.department_id
        FROM employees e
        JOIN dept_stats ds ON e.department_id = ds.department_id
        WHERE e.salary > ds.avg_sal
    )
SELECT * FROM high_paid_employees;
  • dept_stats CTE 计算每个部门的平均工资。
  • high_paid_employees CTE 筛选出工资高于部门平均工资的员工。
  • 最后从 high_paid_employees 中选择数据。

示例 4:CTE 用于更新或删除

CTE 不仅可以用于 SELECT,还可以用于 UPDATEDELETE

假设我们想将工资低于平均工资的员工的工资增加 10%:

WITH avg_salary AS (
    SELECT AVG(salary) AS avg_sal FROM employees
)
UPDATE employees
SET salary = salary * 1.10
WHERE salary < (SELECT avg_sal FROM avg_salary);
  • avg_salary CTE 计算平均工资。
  • UPDATE 语句使用 CTE 的结果来更新符合条件的记录。

注意事项

  1. CTE 的作用范围:CTE 仅在定义它的查询中有效,查询结束后 CTE 就会被销毁。
  2. 性能:CTE 可以提高查询的可读性,但在某些情况下可能会影响性能(尤其是递归 CTE)。
  3. 递归深度:MySQL 对递归 CTE 的深度有限制,默认是 1000 层,可以通过 cte_max_recursion_depth 参数调整。

总结

  • WITH 关键字用于定义 CTE,简化复杂查询。
  • CTE 可以是普通的(非递归)或递归的。
  • CTE 可以用于 SELECTUPDATEDELETE 等操作。
  • 递归 CTE 适合处理层次结构数据(如树形结构)。
### 高级SQL递归查询的用法 递归公用表表达式(Recursive Common Table Expressions, CTEs)是一种强大的工具,用于处理层次结构数据或迭代计算。以下是关于如何使用高级SQL递归查询的一些关键点: #### 初步概念 递归CTE由三个主要部分组成:初始集、递归调用和终止条件。这些组件共同定义了一个自引用的关系[^3]。 ```sql WITH Recursive_CTE AS ( -- Initial Set: 定义基础成员 SELECT ... FROM Base_Table WHERE ... UNION ALL -- Recursive Call: 自身引用并扩展结果集 SELECT ... FROM Recursive_CTE rcte INNER JOIN Some_Other_Table ot ON rcte.Key_Column = ot.Parent_Key_Column WHERE ... -- 终止条件通常在这里实现 ) -- 查询最终的结果 SELECT * FROM Recursive_CTE; ``` #### 实际应用案例 下面是一个更复杂的例子,展示如何利用递归来解决实际问题——例如遍历树形结构中的节点关系。 假设有一个员工表`Employees`,其中包含字段`EmployeeID`, `ManagerID`(指向其上级经理),以及一些其他属性。我们希望找到某个特定员工及其所有下属的信息。 ```sql WITH EmployeeHierarchy AS ( -- 初始化集合:从指定根节点开始 SELECT EmployeeID, ManagerID, Name, Level AS HierarchyLevel FROM Employees WHERE EmployeeID = :Root_Employee_ID UNION ALL -- 递归调用:查找当前记录的所有直接下级 SELECT e.EmployeeID, e.ManagerID, e.Name, eh.HierarchyLevel + 1 AS HierarchyLevel FROM Employees e INNER JOIN EmployeeHierarchy eh ON e.ManagerID = eh.EmployeeID ) SELECT * FROM EmployeeHierarchy; ``` 此脚本不仅返回了给定起始点下的所有子项,还附加了一列表示它们之间的相对深度级别。 #### 查看执行计划以优化性能 当构建复杂递归查询时,了解其运行机制非常重要。可以采用多种方式来分析执行计划,从而改进效率。一种方法就是借助Oracle提供的`DBMS_XPLAN.DISPLAY`函数显示详细的执行细节[^4]。 ```sql EXPLAIN PLAN FOR WITH RecursiveQuery AS (...); SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED')); ``` 上述命令会生成一份详尽报告,帮助识别潜在瓶颈所在之处。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值