mssqlserver 无限级分类存储过程的应用

本文介绍了一个SQL Server数据库中复杂存储过程的设计与实现,包括栏目插入、更新、删除等操作,通过递归方式实现了多级栏目管理,并确保了数据的一致性和事务的完整性。

建成的存储过程

查询结果截图

用到的代码

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Tb_Column]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[Tb_Column] GO Create TABLE [dbo].[Tb_Column] ( [Column_ID] [int] NOT NULL , [Column_Name] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [Parent_ID] [int] NULL , [Column_Path] [nvarchar] (1000) COLLATE Chinese_PRC_CI_AS NULL , [Column_Depth] [int] NULL , [Column_Order] [int] NULL , [Column_Intro] [nvarchar] (1000) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY] GO Alter TABLE [dbo].[Tb_Column] ADD CONSTRAINT [DF_Tb_Column_Parent_ID] DEFAULT (0) FOR [Parent_ID], CONSTRAINT [DF_Tb_Column_Column_Depth] DEFAULT (0) FOR [Column_Depth], CONSTRAINT [DF_Tb_Column_Column_Order] DEFAULT (0) FOR [Column_Order], CONSTRAINT [PK_Tb_Column] PRIMARY KEY CLUSTERED ( [Column_ID] ) ON [PRIMARY] GO exec sp_addextendedproperty N'MS_Description', N'分类深度(默认值0)', N'user', N'dbo', N'table', N'Tb_Column', N'column', N'Column_Depth' GO exec sp_addextendedproperty N'MS_Description', N'int 主键(注:非标识)', N'user', N'dbo', N'table', N'Tb_Column', N'column', N'Column_ID' GO exec sp_addextendedproperty N'MS_Description', N'分类说明', N'user', N'dbo', N'table', N'Tb_Column', N'column', N'Column_Intro' GO exec sp_addextendedproperty N'MS_Description', N'分类名称', N'user', N'dbo', N'table', N'Tb_Column', N'column', N'Column_Name' GO exec sp_addextendedproperty N'MS_Description', N'排序(默认值0)', N'user', N'dbo', N'table', N'Tb_Column', N'column', N'Column_Order' GO exec sp_addextendedproperty N'MS_Description', N'分类路径', N'user', N'dbo', N'table', N'Tb_Column', N'column', N'Column_Path' GO exec sp_addextendedproperty N'MS_Description', N'父分类ID(默认值0)', N'user', N'dbo', N'table', N'Tb_Column', N'column', N'Parent_ID' GO Create PROCEDURE sp_Column_Insert ( @Parent_ID int, @Column_Name nvarchar(50), @Column_Intro nvarchar(1000) ) AS Declare @Err As int Set @Err=0 Begin Tran --通过现有记录获取栏目ID Declare @Column_ID As int Declare @Column_Depth As int Select @Column_ID = Max(Column_ID) From Tb_Column IF @Column_ID Is Not Null Set @Column_ID = @Column_ID+1 Else Set @Column_ID = 1 --判断是否是顶级栏目,设置其Column_Path和Column_Order Declare @Column_Path As nvarchar(1000) Declare @Column_Order As int IF @Parent_ID = 0 Begin Set @Column_Path =Ltrim(Str(@Column_ID)) Select @Column_Order = Max(Column_Order) From Tb_Column IF @Column_Order Is Not Null Set @Column_Order = @Column_Order + 1 Else --如果没有查询到记录,说明这是第一条记录 Set @Column_Order = 1 --深度 Set @Column_Depth = 1 End Else Begin --获取父节点的路径和深度 Select @Column_Path = Column_Path ,@Column_Depth = Column_Depth From Tb_Column Where Column_ID=@Parent_ID IF @Column_Path Is Null Begin Set @Err = 1 Goto theEnd End --获取同父节点下的最大序号 Select @Column_Order = Max(Column_Order) From Tb_Column Where Column_Path like ''+@Column_Path+'|%' or Column_ID = @Parent_ID IF @Column_Order Is Not Null --如果序号存在,那么将该序号后的所有序号都加1 Begin --更新当前要插入节点后所有节点的序号 Update Tb_Column Set Column_Order = Column_Order +1 Where Column_Order >@Column_Order --同父节点下的最大序号加上1,构成自己的序号 Set @Column_Order = @Column_Order + 1 End Else Begin Set @Err=1 Goto theEnd End --父节点的路径加上自己的ID号,构成自己的路径 Set @Column_Path = @Column_Path + '|' + Ltrim(Str(@Column_ID)) --深度 Set @Column_Depth = @Column_Depth+1 End Insert Into Tb_Column(Column_ID,Column_Name,Parent_ID,Column_Path,Column_Depth,Column_Order,Column_Intro) Values(@Column_ID,@Column_Name,@Parent_ID,@Column_Path,@Column_Depth,@Column_Order,@Column_Intro) IF @@Error<>0 Begin Set @Err=1 Goto theEnd End --更新当前记录之后的记录的ORDER --Update Tb_Column Set Column_Order = Column_Order+1 Where Column_Order > @Column_Order theEnd: IF @Err=0 Begin Commit Tran Return @Column_ID End Else Begin Rollback Tran Return 0 End GO Create PROCEDURE sp_Column_Delete ( @Column_ID int ) AS Declare @Err As int Set @Err = 0 Begin Tran --首先查询该节点下是否有子节点 Select Column_ID From Tb_Column Where Parent_ID = @Column_ID IF @@RowCount<>0 Begin Set @Err = 1 Goto theEnd End --获取该节点的Column_Order,为了删除后整理其他记录的顺序 Declare @Column_Order As int Select @Column_Order = Column_Order From Tb_Column Where Column_ID = @Column_ID IF @Column_Order Is NUll Begin Set @Err =2 Goto theEnd End --更新其他记录的Column_Order Update Tb_Column Set Column_Order = Column_Order -1 Where Column_Order >@Column_Order IF @@Error<>0 Begin Set @Err =3 Goto theEnd End --删除操作 Delete From Tb_Column Where Column_ID=@Column_ID IF @@Error<>0 Begin Set @Err =4 Goto theEnd End --更新其他记录的Column_ID --Update Tb_Column Set Column_ID= Column_ID - 1 Where Column_ID >@Column_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 Create PROCEDURE sp_Column_Update ( @Column_ID int, @Parent_ID int, @Column_Name nvarchar(50), @Column_Intro nvarchar(1000) ) AS Declare @Err As int Set @Err=0 Begin Tran --获取修改前的:Parent_ID,Column_Depth,Column_Order Declare @oParent_ID As int Declare @oColumn_Depth As int Declare @oColumn_Order As int Declare @oColumn_Path As nvarchar(1000) Select @oParent_ID = Parent_ID, @oColumn_Depth = Column_Depth,@oColumn_Order = Column_Order, @oColumn_Path = Column_Path From Tb_Column Where Column_ID = @Column_ID IF @oParent_ID Is Null Begin Set @Err = 1 Goto theEnd End --如果父ID没有改变,则直接修改栏目名和栏目简介 IF @oParent_ID = @Parent_ID Begin Update Tb_Column Set Column_Name = @Column_Name,Column_Intro = @Column_Intro Where Column_ID = @Column_ID IF @@Error <> 0 Set @Err = 2 Goto theEnd End Declare @nColumn_Path As nvarchar(1000) Declare @nColumn_Depth As int Declare @nColumn_Order As int --获取当前节点作为父节点所包含的节点数[包括自身] 注:如果返回 “1” 说明是单节点 Declare @theCount As int Select @theCount = Count(Column_ID) From Tb_Column Where Column_ID=@Column_ID or Column_Path like ''+@oColumn_Path+'|%' IF @theCount Is Null Begin Set @Err = 3 Goto theEnd End IF @Parent_ID=0 --如果是设置为顶级节点,将节点设置为最后一个顶级节点 Begin --Print '设置为顶级栏目' Set @nColumn_Path = Ltrim(Str(@Column_ID)) Set @nColumn_Depth =1 Select @nColumn_Order = Max(Column_Order) From Tb_Column IF @nColumn_Order Is NULL Begin Set @Err = 4 Goto theEnd End Set @nColumn_Order = @nColumn_Order - @theCount + 1 --更新三部分 1 节点本身 2 所有子节点 2 本树更改之前的后面记录的顺序 --Print '更新本栏目之前位置后面的所有栏目[不包括本栏目下的子栏目]的:Column_Order' Update Tb_Column Set Column_Order = Column_Order-@theCount Where (Column_Order >@oColumn_Order) And (Column_Path Not like ''+@oColumn_Path+'|%') IF @@Error <> 0 Begin Set @Err = 7 Goto theEnd End --Print '更新本栏目的:Parent_ID,Column_Path,Column_Depth,Column_Order,Column_Name,Column_Intro' Print 'Order : '+Ltrim(Str(@nColumn_Order)) Update Tb_Column Set Parent_ID=@Parent_ID,Column_Path = @nColumn_Path,Column_Depth = @nColumn_Depth,Column_Order = @nColumn_Order, Column_Name = @Column_Name,Column_Intro = @Column_Intro Where Column_ID = @Column_ID IF @@Error <> 0 Begin Set @Err = 5 Goto theEnd End --Print '更新本栏目下的所有子栏目的:Column_Path,Column_Depth,Column_Order' Update Tb_Column Set Column_Path = Replace(Column_Path,@oColumn_Path,@nColumn_Path),Column_Depth = Column_Depth + (@nColumn_Depth-@oColumn_Depth),Column_Order = Column_Order+( @nColumn_Order-@oColumn_Order) Where Column_Path like ''+@oColumn_Path+'|%' IF @@Error <> 0 Begin Set @Err = 6 Goto theEnd End End Else Begin --获取未来父节点的相关信息,并设置本节点的相关值 Select @nColumn_Depth = Column_Depth,@nColumn_Path = Column_Path From Tb_Column Where Column_ID = @Parent_ID IF @nColumn_Depth Is NULL or @nColumn_Path Is Null Begin Set @Err = 8 Goto theEnd End Set @nColumn_Depth = @nColumn_Depth +1 Select @nColumn_Order =Max(Column_Order) From Tb_Column Where Column_ID = @Parent_ID or Column_Path like ''+@nColumn_Path+'|%' IF @nColumn_Order Is NULL Begin Set @Err = 9 Goto theEnd End Set @nColumn_Path = @nColumn_Path +'|'+ Ltrim(Str(@Column_ID)) IF @nColumn_Order = @oColumn_Order+1 --如果新的父节点是原来位置上端最近一个兄弟,则所有节点的顺序都不改变 Begin Update Tb_Column Set Parent_ID=@Parent_ID,Column_Path = @nColumn_Path,Column_Depth = @nColumn_Depth, Column_Name = @Column_Name,Column_Intro = @Column_Intro Where Column_ID = @Column_ID IF @@Error <> 0 Begin Set @Err = 10 Goto theEnd End End Set @nColumn_Order = @nColumn_Order + 1 --更新三部分 1 本树更改之前的后面(或前面)记录的顺序 1 节点本身 3 所有子节点 --分为向上移或象下移 --Print '更新本栏目之前位置后面的所有栏目[或者本栏目之后位置] [不包括本栏目下的子栏目]的:Column_Order' IF @nColumn_Order < @oColumn_Order Begin Update Tb_Column Set Column_Order = Column_Order+@theCount Where Column_Order<@oColumn_Order And Column_Order >=@nColumn_Order And (Column_Path Not like ''+@oColumn_Path+'|%') And Column_ID<>@Column_ID IF @@Error <> 0 Begin Set @Err = 12 Goto theEnd End End Else Begin Update Tb_Column Set Column_Order = Column_Order-@theCount Where Column_Order >@oColumn_Order And Column_Order<@nColumn_Order And (Column_Path Not like ''+@oColumn_Path+'|%') And Column_ID<>@Column_ID IF @@Error <> 0 Begin Set @Err = 13 Goto theEnd End End --Print '更新本栏目的:Parent_ID,Column_Path,Column_Depth,Column_Order,Column_Name,Column_Intro' Print 'Order : '+Ltrim(Str(@nColumn_Order)) IF @nColumn_Order > @oColumn_Order Set @nColumn_Order = @nColumn_Order - @theCount Update Tb_Column Set Parent_ID=@Parent_ID,Column_Path = @nColumn_Path,Column_Depth = @nColumn_Depth,Column_Order = @nColumn_Order, Column_Name = @Column_Name,Column_Intro = @Column_Intro Where Column_ID = @Column_ID IF @@Error <> 0 Begin Set @Err = 10 Goto theEnd End --Print '更新本栏目下的所有子栏目的:Column_Paht,Column_Depth,Column_Order' Update Tb_Column Set Column_Path = Replace(Column_Path,@oColumn_Path,@nColumn_Path),Column_Depth = Column_Depth + (@nColumn_Depth-@oColumn_Depth),Column_Order = Column_Order+(@nColumn_Order-@oColumn_Order) Where Column_Path like ''+@oColumn_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 Create PROCEDURE sp_Column_List AS Select Column_ID, Column_Name, Parent_ID, Column_Path, Column_Depth, Column_Order, Column_Intro FROM Tb_Column orDER BY Column_Order GO --下面是两个执行的例子 exec sp_Column_List exec sp_Column_Insert 9,"中国新闻8","zhoguoxinwen1"

内容概要:本文是一份针对2025年中国企业品牌传播环境撰写的《全网媒体发稿白皮书》,聚焦企业媒体发稿的策略制定、渠道选择与效果评估难题。通过分析当前企业面临的资源分散、内容同质、效果难量化等核心痛点,系统性地介绍了新闻媒体、央媒、地方官媒和自媒体四大渠道的特点与适用场景,并深度融合“传声港”AI驱动的新媒体平台能力,提出“策略+工具+落地”的一体化解决方案。白皮书详细阐述了传声港在资源整合、AI智能匹配、舆情监测、合规审核及全链路效果追踪方面的技术优势,构建了涵盖曝光、互动、转化与品牌影响力的多维评估体系,并通过快消、科技、零售等行业的实战案例验证其有效性。最后,提出了按企业发展阶段和营销节点定制的媒体组合策略,强调本土化传播与政府关系协同的重要性,助力企业实现品牌声量与实际转化的双重增长。; 适合人群:企业市场部负责人、品牌方管理者、公关传播从业者及从事数字营销的相关人员,尤其适用于初创期至成熟期不同发展阶段的企业决策者。; 使用场景及目标:①帮助企业科学制定媒体发稿策略,优化预算分配;②解决渠道对接繁琐、投放不精准、效果不可衡量等问题;③指导企业在重大营销节点(如春节、双11)开展高效传播;④提升品牌权威性、区域渗透力与危机应对能力; 阅读建议:建议结合自身企业所处阶段和发展目标,参考文中提供的“传声港服务组合”与“预算分配建议”进行策略匹配,同时重视AI工具在投放、监测与优化中的实际应用,定期复盘数据以实现持续迭代。
先展示下效果 https://pan.quark.cn/s/987bb7a43dd9 VeighNa - By Traders, For Traders, AI-Powered. Want to read this in english ? Go here VeighNa是一套基于Python的开源量化交易系统开发框架,在开源社区持续不断的贡献下一步步成长为多功能量化交易平台,自发布以来已经积累了众多来自金融机构或相关领域的用户,包括私募基金、证券公司、期货公司等。 在使用VeighNa进行二次开发(策略、模块等)的过程中有任何疑问,请查看VeighNa项目文档,如果无法解决请前往官方社区论坛的【提问求助】板块寻求帮助,也欢迎在【经验分享】板块分享你的使用心得! 想要获取更多关于VeighNa的资讯信息? 请扫描下方二维码添加小助手加入【VeighNa社区交流微信群】: AI-Powered VeighNa发布十周年之际正式推出4.0版本,重磅新增面向AI量化策略的vnpy.alpha模块,为专业量化交易员提供一站式多因子机器学习(ML)策略开发、投研和实盘交易解决方案: :bar_chart: dataset:因子特征工程 * 专为ML算法训练优化设计,支持高效批量特征计算与处理 * 内置丰富的因子特征表达式计算引擎,实现快速一键生成训练数据 * Alpha 158:源于微软Qlib项目的股票市场特征集合,涵盖K线形态、价格趋势、时序波动等多维度量化因子 :bulb: model:预测模型训练 * 提供标准化的ML模型开发模板,大幅简化模型构建与训练流程 * 统一API接口设计,支持无缝切换不同算法进行性能对比测试 * 集成多种主流机器学习算法: * Lass...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值