zoukankan      html  css  js  c++  java
  • SQL 递归查询,意淫CTE递归的执行步骤

    今天用到了sql的递归查询。递归查询是CTE语句with xx as(....)实现的。

    假如表Category数据如下。

    我们想查找机枪这个子分类极其层次关系(通过子节点,查询所有层级节点)。以下是查询语句

    WITH tt AS (
    
    SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=15  --定位点成员
    UNION ALL
    SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId  --递归成员
    
    )
    
    SELECT * FROM tt
    

     执行结果

    CTE递归说明:

    上面的脚本,我注明了定位点成员,和递归成员。

    定位点成员形成了查询的基本结果集。其实就是你用于查询的"引子"数据。在递归cte开始执行时,第一次执行,会先执行定位成员,并得到寄出结果集。

    递归成员是每次递归执行的语句。个人意淫,每次递归时,是把上一次递归查询得出的结果集传递给递归语句,并继续执行递归

    在递归时,如果上一次查询没有返回结果集,则终止递归。(这点让我纠结很久,因为没有显示的著名何时结束递归~)

    意淫的执行步骤--------------------

    首先执行定位成员:

    SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=46

    并得到了结果集:

     

    然后执行第一次递归:

    SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId

    执行递归时,join了 cte 语句本身,就是tt,join里的语句跟with as里的语句一样。其实语句可以意淫成酱紫

    SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    (
    			--SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=15  华丽的忽略掉了
    			--UNION ALL  华丽的忽略掉了
    			SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --我们继续递归~
    	
    )tt ON tt.Parent=c.CategoryId
    

    这次递归可以拆分成两个操作,查询结果和继续递归。

    1.因为是第一次递归,所以将执行定位成员得出的结果集带入,进行查询。其实执行的是酱紫

    SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    (
    		SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=46
    	
    )tt ON tt.Parent=c.CategoryId
    

    发现有结果:

    则继续进行递归:

    递归时语句还是酱紫:

    SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    (
    			--SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=15  华丽的忽略掉了
    			--UNION ALL  华丽的忽略掉了
    			SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --我们继续递归
    	
    )tt ON tt.Parent=c.CategoryId
    

    这次递归查询,所用的结果集是上次递归查询得出的(不再是定位成员的结果集了)。就是用的下面这个结果集

    执行语句是酱紫的

    SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    (
    		SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    	(
    			SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=46
    	
    	)tt ON tt.Parent=c.CategoryId
    )tt ON tt.Parent=c.CategoryId
    

    第一层join的数据是上次递归查询的语句。

    发现有结果:

    ok继续递归吧

    继续上面的步骤,带入上次查询的结果集进行查询。

    执行语句其实是酱紫:

    SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    (
    		SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    		(
    					SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN 
    				(
    							SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=46
    	
    				)tt ON tt.Parent=c.CategoryId
    		)tt ON tt.Parent=c.CategoryId
    )tt ON tt.Parent=c.CategoryId
    

    得出的结果集:

    啥也木有,终止递归。

    然后用union all 把每次递归的结果集合起来。得出了最终的查询结果。

    这个步骤是意淫的,我还设想了其他的方式。但在终止递归上都存在问题,所以最终把文章写成酱紫。

    参考文章:https://www.cnblogs.com/youngmin/p/6256478.html

  • 相关阅读:
    Codeforces Round #562 (Div. 2) B. Pairs
    Codeforces Round #562 (Div. 2) A.Circle Metro
    K.河北美食
    H.天神的密码
    国标GB28181协议智能分析告警平台EasyGBS及EasyCVR监控系统内iframe的常见问题说明
    【解决方案】国标GB28181平台EasyGBS级联EasyCVR视频智能分析搭建“蓝天卫士”网络视频监控系统技术方案
    【解决方案】基于国标GB28181协议/HIKSDK/Ehome协议EasyCVR智能融合分析平台在智慧校园人脸识别中的应用
    TSINGSEE青犀视频基于开源Webrtc服务器编译mediasoupClient运行报”SignalEncoderTimeOut, Encoder timed out”
    TSINGSEE青犀视频云边端H265播放器EasyPlayer-RTSP在C#版本增加OSD功能说明
    TSINGSEE青犀视频自主研发的H265播放器被集成后无法播放视频是什么原因?
  • 原文地址:https://www.cnblogs.com/MLGB/p/7921579.html
Copyright © 2011-2022 走看看