Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 12.0.0 (中文) » SQL Anywhere 服务器 - SQL 的用法 » 查询和修改数据 » 公用表表达式

 

递归公用表表达式

公用表表达式可以是递归的。当 RECURSIVE 关键字紧跟在 WITH 后面出现时,公用表表达式是递归的。一个 WITH 子句可以包含多个递归表达式,并且可以同时包含递归公用表表达式和非递归公用表表达式。

递归提供了更加容易的方法来遍历呈现树状或类似树状的数据结构的表。在不使用递归表达式的情况下使用一个语句遍历这种结构的唯一方法是针对每个可能的级别让表与它自身连接一次。例如,如果报告层次最多包含七个级别,您必须将 Employees 表与它自身连接七次。如果公司进行重组并且引入了一个新的管理级别,您必须重写查询。

递归公用表表达式提供了一种方便的方法来编写将关系返回到任意深度的查询。例如,假定有一个呈现公司内的报告关系的表,您可以很容易地编写一个查询,让它返回向某特定人员报告的所有雇员。

如,以确定哪个部门的雇员数量最多的问题为例。SQL Anywhere 示例数据库中的 Employees 表列出了一家虚构公司内的所有雇员,并指定了每名雇员的工作部门。以下查询列出部门 ID 代码以及各部门中的雇员总数。

SELECT DepartmentID, COUNT( * ) AS n
FROM Employees
GROUP BY DepartmentID;

此查询可用于提取雇员最多的部门,如下所示:

SELECT DepartmentID, n
FROM ( SELECT DepartmentID, COUNT( * ) AS n
       FROM Employees GROUP BY DepartmentID ) AS a
WHERE a.n =
  ( SELECT MAX( n )
    FROM ( SELECT DepartmentID, COUNT( * ) AS n
           FROM Employees GROUP BY DepartmentID ) AS b );

虽然此语句提供了正确的结果,但它有几个缺点。第一个缺点是重复的子查询会降低此语句的效率。第二个缺点是此语句没有在子查询之间提供清楚的链接。

解决这些问题的一个方法是创建一个视图,然后使用该视图重新表达查询。这种方法可避免上述问题。

CREATE VIEW CountEmployees( DepartmentID, n ) AS
   SELECT DepartmentID, COUNT( * ) AS n
   FROM Employees GROUP BY DepartmentID; 

SELECT DepartmentID, n
   FROM CountEmployees
   WHERE n = ( SELECT MAX( n )
               FROM CountEmployees );

这种方法的缺点是需要一些开销,因为数据库服务器必须在创建视图时更新系统表。如果经常使用该视图,则使用这种方法是合理的。但是,如果只在特定 SELECT 语句中使用一次该视图,则首选方法是改为使用公用表表达式。有关公用表表达式的详细信息,请参见使用公用表表达式

递归公用表表达式包含一个初始子查询(也就是种子)以及一个在每次迭代期间给结果集追加其它行的递归子查询。连接这两个部分只能使用运算符 UNION ALL。初始子查询是普通的非递归查询,首先得到处理。递归部分包含对上一次迭代期间添加的行的引用。只要迭代不生成新行,递归就会自动停止。对于在上一次迭代之前选择的行,无法引用。

递归子查询的选择列表必须在编号和数据类型方面都与初始子查询的选择列表匹配。如果无法执行数据类型的自动转换,可显式转换一个子查询的结果,以便它们与其它子查询的结果匹配。


选择分层数据
递归公用表表达式的限制