SQL无限分类存储过程整理1

优点:字段较少,有增删改查功能,不过查询太笼统。

缺点:

1.不算是在很正的无限分类,ClassPath这个字段定义限制。

2.主键CLASSID不是自增的,使用CODESMITH批量生成多层架构代码中会导致出错。

 

 

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[ArticleClass]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[ArticleClass]
GO

CREATE TABLE [dbo].[ArticleClass] (
 [ClassID] [int]  IDENTITY (1, 1) NOT NULL ,--主键(注:非标识)
 [ClassName] [nvarchar] (50) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL,--分类名称
 [ParentID] [int] NOT NULL ,--父分类ID(默认值0)
 [ClassPath] [nvarchar] (1000) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,--分类路径
 [ClassDepth] [int] NOT NULL ,--分类深度(默认值0)
 [ClassOrder] [int] NOT NULL ,--分排序(默认值0)
 [ClassDescription] [nvarchar] (1000) COLLATE Chinese_Taiwan_Stroke_CI_AS NULL ,--分类说明
 [iSystem] [int] NULL --是否是系统默认分类
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[ArticleClass] ADD
 CONSTRAINT [DF_ArticleClass_ParentID] DEFAULT (0) FOR [ParentID],
 CONSTRAINT [DF_ArticleClass_ClassDepth] DEFAULT (0) FOR [ClassDepth],
 CONSTRAINT [DF_ArticleClass_ClassOrder] DEFAULT (0) FOR [ClassOrder],
 CONSTRAINT [DF_ArticleClass_iSystem] DEFAULT (0) FOR [iSystem],
 CONSTRAINT [PK_ArticleClass] PRIMARY KEY  CLUSTERED
 (
 [ClassID]
 )  ON [PRIMARY]
GO
exec sp_addextendedproperty N'MS_Description', N'主键(非标识)', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'ClassID'
GO
exec sp_addextendedproperty N'MS_Description', N'分类名称', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'ClassName'
GO
exec sp_addextendedproperty N'MS_Description', N'父分类ID', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'ParentID'
GO
exec sp_addextendedproperty N'MS_Description', N'分类路径', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'ClassPath'
GO
exec sp_addextendedproperty N'MS_Description', N'分类深度', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'ClassDepth'
GO
exec sp_addextendedproperty N'MS_Description', N'分类排序', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'ClassOrder'
GO
exec sp_addextendedproperty N'MS_Description', N'分类说明', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'ClassDescription'
GO
exec sp_addextendedproperty N'MS_Description', N'是否是系统分类', N'user', N'dbo', N'table', N'ArticleClass', N'column', N'iSystem'


GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_Insert_ArticleClass]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_Insert_ArticleClass]
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO

--新建分类的存储过程
/*
exec  sp_Insert_ArticleClass 0, '農業及漁業','Agriculture and Fishing'
exec  sp_Insert_ArticleClass 1, '農作物種植業','Agriculture and Fishing'
exec  sp_Insert_ArticleClass 2, '蔬菜種植業','Agriculture and Fishing'
exec  sp_Insert_ArticleClass 3, '蔬菜的種植','Agriculture and Fishing'
exec  sp_Insert_ArticleClass 2, '其他農作物種植業','Agriculture and Fishing'
exec  sp_Insert_ArticleClass 4, '花卉的種植','Agriculture and Fishing'
exec  sp_Insert_ArticleClass 4, '㈬果的種植','Agriculture and Fishing'
exec  sp_Insert_ArticleClass 4, '其他農作物的種植','Agriculture and Fishing'
*/

--exec  sp_Delete_ArticleClass 2
--select * from ArticleClass

CREATE PROCEDURE sp_Insert_ArticleClass
(
@ParentID int,
@ClassName nvarchar(50),
@ClassDescription nvarchar(1000)
)
AS

Declare @Err As int

Set @Err=0

Begin Tran

--通过现有记录获取栏目ID

Declare @ClassID As int

Declare @ClassDepth As int

Select @ClassID = Max(ClassID) From ArticleClass

IF @ClassID Is Not Null

Set @ClassID = @ClassID+1

Else

Set @ClassID = 1

--判断是否是顶级栏目,设置其ClassPath和ClassOrder

Declare @ClassPath As nvarchar(1000)

Declare @ClassOrder As int

IF @ParentID = 0

Begin

Set @ClassPath =Ltrim(Str(@ClassID))

Select @ClassOrder = Max(ClassOrder) From ArticleClass

IF @ClassOrder Is Not Null

Set @ClassOrder = @ClassOrder + 1

Else --如果没有查询到记录,说明这是第一条记录

Set @ClassOrder = 1

--深度

Set @ClassDepth = 1

End

Else

Begin

--获取父节点的路径和深度

Select @ClassPath = ClassPath ,@ClassDepth = ClassDepth From ArticleClass Where ClassID=@ParentID

IF @ClassPath Is Null

Begin

Set @Err = 1

Goto theEnd

End

--获取同父节点下的最大序号

Select @ClassOrder = Max(ClassOrder) From ArticleClass Where ClassPath like ''+@ClassPath+'%' Or ClassID = @ParentID
IF @ClassOrder Is Not Null --如果序号存在,那么将该序号后的所有序号都加1
Begin
--更新当前要插入节点后所有节点的序号
Update ArticleClass Set ClassOrder = ClassOrder +1 Where ClassOrder>@ClassOrder
--同父节点下的最大序号加上1,构成自己的序号
Set @ClassOrder = @ClassOrder + 1
End
Else
Begin
Set @Err=1
Goto theEnd
End
--父节点的路径加上自己的ID号,构成自己的路径
Set @ClassPath = @ClassPath + ',' + Ltrim(Str(@ClassID))
--深度
Set @ClassDepth = @ClassDepth+1
End

Insert Into ArticleClass(ClassID,ClassName,ParentID,ClassPath,ClassDepth,ClassOrder,ClassDescription) Values(@ClassID,@ClassName,@ParentID,@ClassPath,@ClassDepth,@ClassOrder,@ClassDescription)

IF @@Error<>0

Begin

Set @Err=1

Goto theEnd

End

--更新当前记录之后的记录的ORDER

--Update ArticleClass Set ClassOrder = ClassOrder+1 Where ClassOrder > @ClassOrder

theEnd:

IF @Err=0

Begin

Commit Tran

Return @ClassID

End

Else

Begin

Rollback Tran

Return 0

End

GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_Delete_ArticleClass]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_Delete_ArticleClass]
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
--删除分类存储过程
--exec  sp_Delete_ArticleClass 1
--select * from ArticleClass
CREATE PROCEDURE sp_Delete_ArticleClass
(
@ClassID int
)

AS

Declare @Err As int

Set @Err = 0

Begin Tran

--首先查询该节点下是否有子节点

Select ClassID From ArticleClass Where ParentID = @ClassID

IF @@RowCount<>0

Begin

Set @Err = 1

Goto theEnd

End

--获取该节点的ClassOrder,为了删除后整理其他记录的顺序

Declare @ClassOrder As int

Select @ClassOrder = ClassOrder From ArticleClass Where ClassID = @ClassID

IF @ClassOrder Is NUll

Begin

Set @Err =2

Goto theEnd

End

--更新其他记录的ClassOrder

Update ArticleClass Set ClassOrder = ClassOrder -1 Where ClassOrder >@ClassOrder

IF @@Error<>0

Begin

Set @Err =3

Goto theEnd

End

--删除操作

Delete From ArticleClass Where ClassID=@ClassID

IF @@Error<>0

Begin

Set @Err =4

Goto theEnd

End

--更新其他记录的ClassID

--Update ArticleClass Set ClassID= ClassID - 1 Where ClassID >@ClassID


--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

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_Update_ArticleClass]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_Update_ArticleClass]
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
--更新分类记录的存储过程
--exec sp_Update_ArticleClass @ClassID,@ParentID,@ClassName,@ClassDescription
--select * from ArticleClass
CREATE PROCEDURE sp_Update_ArticleClass
(
@ClassID int,
@ParentID int,
@ClassName nvarchar(50),
@ClassDescription nvarchar(1000)
)

AS

Declare @Err As int

Set @Err=0

Begin Tran

--获取修改前的:ParentID,ClassDepth,ClassOrder

Declare @oParentID As int

Declare @oClassDepth As int

Declare @oClassOrder As int

Declare @oClassPath As nvarchar(1000)

Select @oParentID = ParentID, @oClassDepth = ClassDepth,@oClassOrder= ClassOrder, @oClassPath = ClassPath From ArticleClass Where ClassID= @ClassID

IF @oParentID Is Null

Begin

Set @Err = 1

Goto theEnd

End

--如果父ID没有改变,则直接修改栏目名和栏目简介

IF @oParentID = @ParentID

Begin

Update ArticleClass Set ClassName = @ClassName,ClassDescription = @ClassDescription Where ClassID = @ClassID

IF @@Error <> 0

Set @Err = 2

Goto theEnd

End


Declare @nClassPath As nvarchar(1000)

Declare @nClassDepth As int

Declare @nClassOrder As int

--获取当前节点作为父节点所包含的节点数[包括自身] 注:如果返回 “1” 说明是单节点

Declare @theCount As int

Select @theCount = Count(ClassID) From ArticleClass Where ClassID=@ClassID Or ClassPath like ''+@oClassPath+'%'

IF @theCount Is Null

Begin

Set @Err = 3

Goto theEnd

End

IF @ParentID=0 --如果是设置为顶级节点,将节点设置为最后一个顶级节点

Begin

--Print '设置为顶级栏目'

Set @nClassPath = Ltrim(Str(@ClassID))

Set @nClassDepth =1

Select @nClassOrder = Max(ClassOrder) From ArticleClass

IF @nClassOrder Is NULL

Begin

Set @Err = 4

Goto theEnd

End

Set @nClassOrder = @nClassOrder - @theCount + 1

--更新三部分 1 节点本身 2 所有子节点 2 本树更改之前的后面记录的顺序

--Print '更新本栏目之前位置后面的所有栏目[不包括本栏目下的子栏目]的:ClassOrder'

Update ArticleClass Set ClassOrder = ClassOrder-@theCount Where (ClassOrder >@oClassOrder) And (ClassPath Not like ''+@oClassPath+'%')

IF @@Error <> 0

Begin

Set @Err = 7

Goto theEnd

End

--Print '更新本栏目的:ParentID,ClassPath,ClassDepth,ClassOrder,ClassName,ClassDescription'

Print 'Order : '+Ltrim(Str(@nClassOrder))

Update ArticleClass Set ParentID=@ParentID,ClassPath = @nClassPath,ClassDepth = @nClassDepth,ClassOrder = @nClassOrder, ClassName = @ClassName,ClassDescription = @ClassDescription Where ClassID = @ClassID

IF @@Error <> 0

Begin

Set @Err = 5

Goto theEnd

End

--Print '更新本栏目下的所有子栏目的:ClassPath,ClassDepth,ClassOrder'

Update ArticleClass Set ClassPath = Replace(ClassPath,@oClassPath,@nClassPath),ClassDepth = ClassDepth + (@nClassDepth-@oClassDepth),ClassOrder = ClassOrder+( @nClassOrder-@oClassOrder) Where ClassPath like ''+@oClassPath+'%'

IF @@Error <> 0

Begin

Set @Err = 6

Goto theEnd

End


End

Else

Begin

--获取未来父节点的相关信息,并设置本节点的相关值

Select @nClassDepth = ClassDepth,@nClassPath = ClassPath From ArticleClass Where ClassID = @ParentID

IF @nClassDepth Is NULL Or @nClassPath Is Null

Begin

Set @Err = 8

Goto theEnd

End

Set @nClassDepth = @nClassDepth +1

Select @nClassOrder =Max(ClassOrder) From ArticleClass Where ClassID = @ParentID Or ClassPath like ''+@nClassPath+'%'

IF @nClassOrder Is NULL

Begin

Set @Err = 9

Goto theEnd

End

Set @nClassPath = @nClassPath +''+ Ltrim(Str(@ClassID))

IF @nClassOrder = @oClassOrder+1 --如果新的父节点是原来位置上端最近一个兄弟,则所有节点的顺序都不改变

Begin

Update ArticleClass Set ParentID=@ParentID,ClassPath = @nClassPath,ClassDepth = @nClassDepth, ClassName = @ClassName,ClassDescription = @ClassDescription Where ClassID = @ClassID

IF @@Error <> 0

Begin

Set @Err = 10

Goto theEnd

End

End

Set @nClassOrder = @nClassOrder + 1

--更新三部分 1 本树更改之前的后面(或前面)记录的顺序 1 节点本身 3 所有子节 点

--分为向上移或象下移

--Print '更新本栏目之前位置后面的所有栏目[或者本栏目之后位置] [不包括本栏目下的子栏目]的:ClassOrder'

IF @nClassOrder < @oClassOrder

Begin

Update ArticleClass Set ClassOrder = ClassOrder+@theCount Where ClassOrder<@oClassOrder And ClassOrder >=@nClassOrder And (ClassPath Not like ''+@oClassPath+'%') And ClassID<>@ClassID

IF @@Error <> 0

Begin

Set @Err = 12

Goto theEnd

End

End

Else

Begin

Update ArticleClass Set ClassOrder = ClassOrder-@theCount Where ClassOrder >@oClassOrder And ClassOrder<@nClassOrder And (ClassPath Not like ''+@oClassPath+'%') And ClassID<>@ClassID

IF @@Error <> 0

Begin

Set @Err = 13

Goto theEnd

End

End

--Print '更新本栏目的:ParentID,ClassPath,ClassDepth,ClassOrder,ClassName,ClassDescription'

Print 'Order : '+Ltrim(Str(@nClassOrder))

IF @nClassOrder > @oClassOrder

Set @nClassOrder = @nClassOrder - @theCount

Update ArticleClass Set ParentID=@ParentID,ClassPath = @nClassPath,ClassDepth = @nClassDepth,ClassOrder = @nClassOrder, ClassName = @ClassName,ClassDescription = @ClassDescription Where ClassID = @ClassID

IF @@Error <> 0

Begin

Set @Err = 10

Goto theEnd

End

--Print '更新本栏目下的所有子栏目的:Column_Paht,ClassDepth,ClassOrder'

Update ArticleClass Set ClassPath = Replace(ClassPath,@oClassPath,@nClassPath),ClassDepth = ClassDepth + (@nClassDepth-@oClassDepth),ClassOrder = ClassOrder+(@nClassOrder-@oClassOrder) Where ClassPath like ''+@oClassPath+'%'

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

GO

posted on 2009-09-27 17:27  风灵溪清  阅读(131)  评论(0编辑  收藏  举报

导航