无限级分类 父节点 子节点

简介:

曾祥展

创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
if exists ( select  * from  dbo.sysobjects where  id = object_id(N '[dbo].[Class]' ) and  OBJECTPROPERTY(id, N 'IsUserTable' ) = 1)
drop  table  [dbo].[Class]
GO
Create  TABLE  [dbo].[Class] (
[Class_Id] [ int ] NOT  NULL  ,
[Class_Name] [nvarchar] (50) COLLATE  Chinese_PRC_CI_AS NULL  ,
[Parent_ID] [ int ] NULL  ,
[Class_Path] [nvarchar] (50) COLLATE  Chinese_PRC_CI_AS NULL  ,
[Class_Depth] [ int ] NULL  ,
[Class_Order] [ int ] NULL  ,
[Class_Intro] [nvarchar] (100) COLLATE  Chinese_PRC_CI_AS NULL
) ON  [ PRIMARY ]
GO
Alter  TABLE  [dbo].[Class] ADD
CONSTRAINT  [DF_Class_Parent_ID] DEFAULT  (0) FOR  [Parent_ID],
CONSTRAINT  [DF_Class_Class_Depth] DEFAULT  (0) FOR  [Class_Depth],
CONSTRAINT  [DF_Class_Class_Order] DEFAULT  (0) FOR  [Class_Order],
CONSTRAINT  [PK_Class] PRIMARY  KEY  CLUSTERED
(
[Class_Id]
) ON  [ PRIMARY ]
GO
exec  sp_addextendedproperty N 'MS_Description' , N '分类深度(默认值0)' , N 'user' , N 'dbo' , N 'table' , N 'Class' , N 'column' , N 'Class_Depth'
GO
exec  sp_addextendedproperty N 'MS_Description' , N 'int 主键(注:非标识)' , N 'user' , N 'dbo' , N 'table' , N 'Class' , N 'column' , N 'Class_Id'
GO
exec  sp_addextendedproperty N 'MS_Description' , N '分类说明' , N 'user' , N 'dbo' , N 'table' , N 'Class' , N 'column' , N 'Class_Intro'
GO
exec  sp_addextendedproperty N 'MS_Description' , N '分类名称' , N 'user' , N 'dbo' , N 'table' , N 'Class' , N 'column' , N 'Class_Name'
GO
exec  sp_addextendedproperty N 'MS_Description' , N '排序(默认值0)' , N 'user' , N 'dbo' , N 'table' , N 'Class' , N 'column' , N 'Class_Order'
GO
exec  sp_addextendedproperty N 'MS_Description' , N '分类路径' , N 'user' , N 'dbo' , N 'table' , N 'Class' , N 'column' , N 'Class_Path'
GO
exec  sp_addextendedproperty N 'MS_Description' , N '父分类ID(默认值0)' , N 'user' , N 'dbo' , N 'table' , N 'Class' , N 'column' , N 'Parent_ID'

 

 

增加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
Create  PROCEDURE  sp_Class_Insert
(
@Parent_ID int ,
@Class_Name nvarchar(50),
@Class_Intro nvarchar(1000)
)
AS
Declare  @Err As  int
Set  @Err=0
Begin  Tran
--通过现有记录获取栏目ID
Declare  @Class_Id As  int
Declare  @Class_Depth As  int
Select  @Class_Id = Max (Class_Id) From  Class
IF @Class_Id Is  Not  Null
Set  @Class_Id = @Class_Id+1
Else
Set  @Class_Id = 1
--判断是否是顶级栏目,设置其Class_Path和Class_Order
Declare  @Class_Path As  nvarchar(1000)
Declare  @Class_Order As  int
IF @Parent_ID = 0
Begin
Set  @Class_Path =Ltrim(Str(@Class_Id))
Select  @Class_Order = Max (Class_Order) From  Class
IF @Class_Order Is  Not  Null
Set  @Class_Order = @Class_Order + 1
Else  --如果没有查询到记录,说明这是第一条记录
Set  @Class_Order = 1
--深度
Set  @Class_Depth = 1
End
Else
Begin
--获取父节点的路径和深度
Select  @Class_Path = Class_Path ,@Class_Depth = Class_Depth From  Class Where
Class_Id=@Parent_ID
IF @Class_Path Is  Null
Begin
Set  @Err = 1
Goto  theEnd
End
--获取同父节点下的最大序号
Select  @Class_Order = Max (Class_Order) From  Class Where  Class_Path like
'' +@Class_Path+ '|%'  or  Class_Id = @Parent_ID
IF @Class_Order Is  Not  Null  --如果序号存在,那么将该序号后的所有序号都加1
Begin
--更新当前要插入节点后所有节点的序号
Update  Class Set  Class_Order = Class_Order +1 Where  Class_Order
>@Class_Order
--同父节点下的最大序号加上1,构成自己的序号
Set  @Class_Order = @Class_Order + 1
End
Else
Begin
Set  @Err=1
Goto  theEnd
End
--父节点的路径加上自己的ID号,构成自己的路径
Set  @Class_Path = @Class_Path + '|'  + Ltrim(Str(@Class_Id))
--深度
Set  @Class_Depth = @Class_Depth+1
End
Insert  Into  Class(Class_Id,Class_Name,Parent_ID,Class_Path,Class_Depth,Class_Order,Class_Intro)
Values (@Class_Id,@Class_Name,@Parent_ID,@Class_Path,@Class_Depth,@Class_Order,@Class_Intro)
IF @@Error<>0
Begin
Set  @Err=1
Goto  theEnd
End
--更新当前记录之后的记录的ORDER
--Update Class Set Class_Order = Class_Order+1 Where Class_Order > @Class_Order
theEnd:
IF @Err=0
Begin
Commit  Tran
Return  @Class_Id
End
Else
Begin
Rollback  Tran
Return  0
End
GO

 

删除:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Create  PROCEDURE  sp_Class_Delete
(
@Class_Id int
)
AS
Declare  @Err As  int
Set  @Err = 0
Begin  Tran
--首先查询该节点下是否有子节点
Select  Class_Id From  Class Where  Parent_ID = @Class_Id
IF @@RowCount<>0
Begin
Set  @Err = 1
Goto  theEnd
End
--获取该节点的Class_Order,为了删除后整理其他记录的顺序
Declare  @Class_Order As  int
Select  @Class_Order = Class_Order From  Class Where  Class_Id = @Class_Id
IF @Class_Order Is  NUll
Begin
Set  @Err =2
Goto  theEnd
End
--更新其他记录的Class_Order
Update  Class Set  Class_Order = Class_Order -1 Where  Class_Order >@Class_Order
IF @@Error<>0
Begin
Set  @Err =3
Goto  theEnd
End
--删除操作
Delete  From  Class Where  Class_Id=@Class_Id
IF @@Error<>0
Begin
Set  @Err =4
Goto  theEnd
End
--更新其他记录的Class_Id
--Update Class Set Class_Id= Class_Id - 1 Where Class_Id >@Class_Id
--IF @@Error<>0
-- Begin
-- Set @Err =5
-- Goto theEnd
-- End
--
theEnd:
IF @Err = 0
Begin
Commit  Tran
Return  0 --删除成功
End
Else
Begin
IF @Err=1
Begin
Rollback  Tran
Return  1 --有子节点
End
Else
Begin
Rollback  Tran
Return  2 --未知错误
End
End
GO

 

 

 

 

更新:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
Create  PROCEDURE  sp_Class_Update
(
@Class_Id int ,
@Parent_ID int ,
@Class_Name nvarchar(50),
@Class_Intro nvarchar(1000)
)
AS
Declare  @Err As  int
Set  @Err=0
Begin  Tran
--获取修改前的:Parent_ID,Class_Depth,Class_Order
Declare  @oParent_ID As  int
Declare  @oClass_Depth As  int
Declare  @oClass_Order As  int
Declare  @oClass_Path As  nvarchar(1000)
Select  @oParent_ID = Parent_ID, @oClass_Depth = Class_Depth,@oClass_Order = Class_Order, @oClass_Path = Class_Path From  Class Where  Class_Id = @Class_Id
IF @oParent_ID Is  Null
Begin
Set  @Err = 1
Goto  theEnd
End
--如果父ID没有改变,则直接修改栏目名和栏目简介
IF @oParent_ID = @Parent_ID
Begin
Update  Class Set  Class_Name = @Class_Name,Class_Intro = @Class_Intro Where  Class_Id = @Class_Id
IF @@Error <> 0
Set  @Err = 2
Goto  theEnd
End
Declare  @nClass_Path As  nvarchar(1000)
Declare  @nClass_Depth As  int
Declare  @nClass_Order As  int
--获取当前节点作为父节点所包含的节点数[包括自身] 注:如果返回 “1” 说明是单节点
Declare  @theCount As  int
Select  @theCount = Count (Class_Id) From  Class Where  Class_Id=@Class_Id or  Class_Path like  '' +@oClass_Path+ '|%'
IF @theCount Is  Null
Begin
Set  @Err = 3
Goto  theEnd
End
IF @Parent_ID=0 --如果是设置为顶级节点,将节点设置为最后一个顶级节点
Begin
--Print '设置为顶级栏目'
Set  @nClass_Path = Ltrim(Str(@Class_Id))
Set  @nClass_Depth =1
Select  @nClass_Order = Max (Class_Order) From  Class
IF @nClass_Order Is  NULL
Begin
Set  @Err = 4
Goto  theEnd
End
Set  @nClass_Order = @nClass_Order - @theCount + 1
--更新三部分 1 节点本身 2 所有子节点 2 本树更改之前的后面记录的顺序
--Print '更新本栏目之前位置后面的所有栏目[不包括本栏目下的子栏目]的:Class_Order'
Update  Class Set  Class_Order = Class_Order-@theCount Where  (Class_Order >@oClass_Order) And  (Class_Path Not  like  '' +@oClass_Path+ '|%' )
IF @@Error <> 0
Begin
Set  @Err = 7
Goto  theEnd
End
--Print '更新本栏目的:Parent_ID,Class_Path,Class_Depth,Class_Order,Class_Name,Class_Intro'
Print 'Order : ' +Ltrim(Str(@nClass_Order))
Update  Class Set  Parent_ID=@Parent_ID,Class_Path = @nClass_Path,Class_Depth = @nClass_Depth,Class_Order = @nClass_Order, Class_Name = @Class_Name,Class_Intro = @Class_Intro Where  Class_Id = @Class_Id
IF @@Error <> 0
Begin
Set  @Err = 5
Goto  theEnd
End
--Print '更新本栏目下的所有子栏目的:Class_Path,Class_Depth,Class_Order'
Update  Class Set  Class_Path = Replace (Class_Path,@oClass_Path,@nClass_Path),Class_Depth = Class_Depth + (@nClass_Depth-@oClass_Depth),Class_Order = Class_Order+( @nClass_Order-@oClass_Order) Where  Class_Path like  '' +@oClass_Path+ '|%'
IF @@Error <> 0
Begin
Set  @Err = 6
Goto  theEnd
End
End
Else
Begin
--获取未来父节点的相关信息,并设置本节点的相关值
Select  @nClass_Depth = Class_Depth,@nClass_Path = Class_Path From  Class Where Class_Id = @Parent_ID
IF @nClass_Depth Is  NULL  or  @nClass_Path Is  Null
Begin
Set  @Err = 8
Goto  theEnd
End
Set  @nClass_Depth = @nClass_Depth +1
Select  @nClass_Order = Max (Class_Order) From  Class Where  Class_Id = @Parent_ID or  Class_Path like  '' +@nClass_Path+ '|%'
IF @nClass_Order Is  NULL
Begin
Set  @Err = 9
Goto  theEnd
End
Set  @nClass_Path = @nClass_Path + '|' + Ltrim(Str(@Class_Id))
IF @nClass_Order = @oClass_Order+1 --如果新的父节点是原来位置上端最近一个兄弟,则所有节点的顺序都不改变
Begin
Update  Class Set  Parent_ID=@Parent_ID,Class_Path = @nClass_Path,Class_Depth = @nClass_Depth, Class_Name = @Class_Name,Class_Intro = @Class_Intro Where  Class_Id = @Class_Id
IF @@Error <> 0
Begin
Set  @Err = 10
Goto  theEnd
End
End
Set  @nClass_Order = @nClass_Order + 1
--更新三部分 1 本树更改之前的后面(或前面)记录的顺序 1 节点本身 3 所有子节点
--分为向上移或象下移
--Print '更新本栏目之前位置后面的所有栏目[或者本栏目之后位置] [不包括本栏目下的子栏目]的:Class_Order'
IF @nClass_Order < @oClass_Order
Begin
Update  Class Set  Class_Order = Class_Order+@theCount Where  Class_Order<@oClass_Order And  Class_Order >=@nClass_Order And  (Class_Path Not like  '' +@oClass_Path+ '|%' ) And  Class_Id<>@Class_Id
IF @@Error <> 0
Begin
Set  @Err = 12
Goto  theEnd
End
End
Else
Begin
Update  Class Set  Class_Order = Class_Order-@theCount Where  Class_Order >@oClass_Order And  Class_Order<@nClass_Order And  (Class_Path Not  like  '' +@oClass_Path+ '|%' ) And  Class_Id<>@Class_Id
IF @@Error <> 0
Begin
Set  @Err = 13
Goto  theEnd
End
End
--Print '更新本栏目的:Parent_ID,Class_Path,Class_Depth,Class_Order,Class_Name,Class_Intro'
Print 'Order : ' +Ltrim(Str(@nClass_Order))
IF @nClass_Order > @oClass_Order
Set  @nClass_Order = @nClass_Order - @theCount
Update  Class Set  Parent_ID=@Parent_ID,Class_Path = @nClass_Path,Class_Depth = @nClass_Depth,Class_Order = @nClass_Order, Class_Name = @Class_Name,Class_Intro = @Class_Intro Where  Class_Id = @Class_Id
IF @@Error <> 0
Begin
Set  @Err = 10
Goto  theEnd
End
--Print '更新本栏目下的所有子栏目的:Class_Paht,Class_Depth,Class_Order'
Update  Class Set  Class_Path = Replace (Class_Path,@oClass_Path,@nClass_Path),Class_Depth = Class_Depth + (@nClass_Depth-@oClass_Depth),Class_Order = Class_Order+(@nClass_Order-@oClass_Order) Where  Class_Path like  '' +@oClass_Path+ '|%'
IF @@Error <> 0
Begin
Set  @Err = 11
Goto  theEnd
End
End
theEnd:
IF @Err<>0 --如果有错误则返回错误号
Begin
Rollback  Tran
Return  @Err
End
Else  --如果没有错误就返回0
Begin
Commit  Tran
Return  0
End

 

 

 

查询:

1
2
3
4
5
6
7
Create  PROCEDURE  sp_Class_List
AS
Select  Class_Id, Class_Name, Parent_ID, Class_Path, Class_Depth,
Class_Order, Class_Intro
FROM  Class
orDER  BY  Class_Order
GO

 

 

 

调用:

1
2
3
4
5
6
exec  sp_Class_Insert 4, "家具4" , "jiaju4"  --parent_id,,,
exec  sp_Class_List
exec  sp_Class_Delete 2
exec  sp_Class_Update 4,2, "家具a" , "jiajua"  --class_id parent_id name ..
select  * from  Class
delete  class from  class where  class_name like  '%家具%'
1
<br>
复制代码
所有父类
declare @sql varchar(max)
select  @sql=  '  SELECT CategoryId,CategoryName,CategoryPath   FROM B_Category 
  WHERE CategoryId IN ( ' +categorypath+ ') '   from B_Category  where CategoryId=53
exec (@sql) 
-- in( 51, 53)
复制代码
    本文转自曾祥展博客园博客,原文链接: http://www.cnblogs.com/zengxiangzhan/archive/2010/01/04/1639220.html ,如需转载请自行联系原作者
相关文章
|
6月前
|
算法
落叶归根:递归思想在二叉树叶子节点类问题中的妙用
落叶归根:递归思想在二叉树叶子节点类问题中的妙用
70 1
ztree判断是否是叶子节点
ztree判断是否是叶子节点
119 0
el-tree技巧之只能选中最后一层级的子节点以及查找树结构第一个无子节点的叶节点
el-tree技巧之只能选中最后一层级的子节点以及查找树结构第一个无子节点的叶节点
|
5月前
【树 - 平衡二叉树(AVL)】F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量
【树 - 平衡二叉树(AVL)】F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量
|
4月前
|
JavaScript
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
119 0
JavaWeb - 查询任意节点的所有子节点(包括孙子节点)
JavaWeb - 查询任意节点的所有子节点(包括孙子节点)
356 0
剑指offer 76. 树中两个结点的最低公共祖先
剑指offer 76. 树中两个结点的最低公共祖先
66 0
【elementUI】el-tree搜索时加载子节点对应父节点、父节点对应子节点树
【elementUI】el-tree搜索时加载子节点对应父节点、父节点对应子节点树
340 0
【elementUI】el-tree搜索时加载子节点对应父节点、父节点对应子节点树
|
JavaScript 前端开发
JavaScript 获取子节点、父节点、兄弟节点方法总结
JavaScript 获取子节点、父节点、兄弟节点方法总结
750 0
JavaScript 获取子节点、父节点、兄弟节点方法总结