Sql中的递归问题
【递归】
是一种循环方式或规则
树的遍历常常用到
优点:编写程序方便
缺点:限制与内存,容易崩溃
【描述】
类别表
CID,CName,FID
FID=0表示此节点为根节点
如何在Sql中应用递归思想
【实践】
实践来分析和建议:
Exec P_IOSaveCategoryInfo 0 ,'Computer' ,0;--return 1
Exec P_IOSaveCategoryInfo 0 ,'CPU' ,1;--return 2
Exec P_IOSaveCategoryInfo 0 ,'Mainboard' ,1;-- return 3
Exec P_IOSaveCategoryInfo 0 ,'Memory' ,1;-- return 4
Exec P_IOSaveCategoryInfo 0 ,'HardDisk' ,1;-- return 5
Exec P_IOSaveCategoryInfo 0 ,'Mouse' ,1;-- return 6
Exec P_IOSaveCategoryInfo 0 ,'Keyboard' ,1;-- return 7
Exec P_IOSaveCategoryInfo 0 ,'ExtendDevice' ,1;-- return 8
Exec P_IOSaveCategoryInfo 0 ,'UsbDisk' ,8;-- return 9
Exec P_IOSaveCategoryInfo 0 ,'SDCard' ,8;-- return 10
Exec P_IOSaveCategoryInfo 0 ,'TFCard' ,8;-- return 11
树的效果图如下:
1
|
--------------------------------------------------
| | | | | | |
2 3 4 5 6 7 8
|
-----------------
| | |
9 10 11
查询一:
根据输入ID获取到此ID和以及旗下的子ID信息
Select
[CID],
[CatName],
[FID],
case when 0 = fid then cid else fid end as nfid
FROM TB
Where Cid = 1 Or FID = 1
Order by nfid ,[FID],[CID];
输出如下:
CID CatName FID nfid
----------- ------------------------- ----------- -----------
1 Computer 0 1
2 CPU 1 1
3 Mainboard 1 1
4 Memory 1 1
5 HardDisk 1 1
6 Mouse 1 1
7 Keyboard 1 1
8 ExtendDevice 1 1
由上可见:每次只能取2级数据
查询二:
尝试取3级数据
Select A.CID ,A.CatName ,B.CID As CID1 ,B.CatName As CatName1 ,Case When C.CID is null Then B.CID Else C.CID End AS CID2 ,Case When C.CID is null Then B.CatName Else C.CatName End AS CatName2
FROM TB A With(Nolock)
Left Join TB B With(Nolock) On B.FID = A.CID
Left Join TB C With(Nolock) On C.FID = B.CID
Where A.CID = 1
输出数据如下:
CID CatName CID1 CatName1 CID2 CatName2
----------- --------------- ----------- ---------------- ----------- ---------------
1 Computer 2 CPU 2 CPU
1 Computer 3 Mainboard 3 Mainboard
1 Computer 4 Memory 4 Memory
1 Computer 5 HardDisk 5 HardDisk
1 Computer 6 Mouse 6 Mouse
1 Computer 7 Keyboard 7 Keyboard
1 Computer 8 ExtendDevice 9 UsbDisk
1 Computer 8 ExtendDevice 10 SDCard
1 Computer 8 ExtendDevice 11 TFCard
由上可见:前两列为一级,中两列为二级,后两列为三级,其中为Null的数据均由其父节点填充
但问题也出现了,不方便查询使用,仅浏览而已。
个人认为:
看来无限级的提取,在Sql语句中也难一次性获取。
建议:
类似此表结构,提取最好采用两级提取(提取本身信息以及子节点信息),业务层处理数据展示关系
特殊需求,如2-4级也可以采用查询二的方式提取,一次性提取所有节点
回到一句老话:见机行事
说到这里,有一点设计的思考可以考虑:
为表新增一个字段,采用varchar,保存父子关系,
如
1,Computer,0,1,10001
2,CPU,1,1,10001-10002
3,Mainboard,1,1,10001-10003
4,Memory,1,1,10001-10004
5,HardDisk,1,1,10001-10005
6,Mouse,1,1,10001-10006
7,Keyboard,1,1,10001-10007
8,ExtendDevice,1,1,10001-10008
9,UsbDisk,8,8,10001-10008-10009
10,SDCard,8,8,10001-10008-10010
11,TFCard,8,8,10001-10008-10011
最后一列,为父子关系图,其中由于长度过于短小不利于定位和查询,特为数据加了10000
这类实现,好处在于一次性提取所有关系数据。缺点,不利于修改关系。适合码表数据的定义,若动态定义此类数据需要谨慎使用。