笔记123 公用表表达式CTE递归调用 辽宁省2012-11-15
笔记123 公用表表达式CTE递归调用 辽宁省2012-11-15
1 --公用表表达式CTE递归调用 辽宁省2012-11-15 2 --http://blog.sina.com.cn/s/blog_a21b662f01019i2g.html 3 --要查询出某个省下面的所有市和区(查询结果包含省) 4 DECLARE @a TABLE(id INT ,node_name VARCHAR(10),parent_id INT) 5 INSERT @a 6 SELECT 1,'辽宁省',0 UNION ALL 7 SELECT 2,'沈阳市',1 UNION ALL 8 SELECT 3,'大连市',1 UNION ALL 9 SELECT 4,'大东区',2 UNION ALL 10 SELECT 5,'沈河区',2 UNION ALL 11 SELECT 6,'铁西区',2 UNION ALL 12 SELECT 7,'山东省',0 13 14 SELECT * FROM @a 15 16 ;with 17 district as 18 ( 19 -- 获得第一个结果集,并更新最终结果集 20 select * from @a where node_name= N'沈阳市' 21 union all 22 -- 下面的select语句首先会根据从上一个查询结果集中获得的id值来查询parent_id 23 -- 字段的值,然后district就会变当前的查询结果集,并继续执行下面的select 语句 24 -- 如果结果集不为null,则与最终的查询结果合并,同时用合并的结果更新最终的查 25 -- 询结果;否则停止执行。最后district的结果集就是最终结果集。 26 select a.* from @a a, district b 27 where a.parent_id = b.id 28 ) 29 select * from district 30 31 32 33 34 35 -- 36 --1. 递归 CTE 定义至少必须包含两个 CTE 查询定义,一个定位点成员和一个递归成员。可以定义多个定位点成员和递归成员;但必须将所有定位点成员查询定义置于第一个递归成员定义之前。所有 CTE 查询定义都是定位点成员,但它们引用 CTE 本身时除外。 37 --2. 定位点成员必须与以下集合运算符之一结合使用:UNION ALL、UNION、INTERSECT 或 EXCEPT。在最后一个定位点成员和第一个递归成员之间,以及组合多个递归成员时,只能使用 UNION ALL 集合运算符。 38 --3. 定位点成员和递归成员中的列数必须一致。 39 --4. 递归成员中列的数据类型必须与定位点成员中相应列的数据类型一致。 40 --5. 递归成员的 FROM 子句只能引用一次 CTE expression_name。 41 --6. 在递归成员的 CTE_query_definition 中不允许出现下列项: 42 -- 43 --(1)SELECT DISTINCT 44 -- 45 --(2)GROUP BY 46 -- 47 --(3)HAVING 48 -- 49 --(4)标量聚合 50 -- 51 --(5)TOP 52 -- 53 --(6)LEFT、RIGHT、OUTER JOIN(允许出现 INNER JOIN) 54 -- 55 --(7)子查询 56 -- 57 --(8)应用于对 CTE_query_definition 中的 CTE 的递归引用的提示。 58 -- 59 --7. 无论参与的 SELECT 语句返回的列的为空性如何,递归 CTE 返回的全部列都可以为空。 60 --8. 如果递归 CTE 组合不正确,可能会导致无限循环。例如,如果递归成员查询定义对父列和子列返回相同的值,则会造成无限循环。可以使用 MAXRECURSION 提示以及在 INSERT、UPDATE、DELETE 或 SELECT 语句的 OPTION 子句中的一个 0 到 32,767 之间的值,来限制特定语句所允许的递归级数,以防止出现无限循环。这样就能够在解决产生循环的代码问题之前控制语句的执行。服务器范围内的默认值是100。如果指定 0,则没有限制。每一个语句只能指定一个 MAXRECURSION 值。 61 --9. 不能使用包含递归公用表表达式的视图来更新数据。 62 --10. 可以使用 CTE 在查询上定义游标。递归 CTE 只允许使用快速只进游标和静态(快照)游标。如果在递归 CTE 中指定了其他游标类型,则该类型将转换为静态游标类型。 63 --11. 可以在 CTE 中引用远程服务器中的表。如果在 CTE 的递归成员中引用了远程服务器,那么将为每个远程表创建一个假脱机,这样就可以在本地反复访问这些表。 64 -- 65 -- 66 --
with testTree (id, parent_id, name, deptLevel) as ( select id, parent_id, name, 0 from Dept where id = 9 union all select a.id, a.parent_id, a.name, b.deptLevel+1 from Dept a inner join testTree b on a.id = b.parent_id ) select * from testTree OPTION(MAXRECURSION 0)