简单实用SQL脚本Part:生成站点导航树形结构

一、需求

我们通常的时候,都是先有站点地图,之后对URL的地址进行判断和导航的,那么我们是否可以根据所有收集到的URL来进行分解,从而生成出所有可能的地址,最主要的是要有一个层级的关系。

我们的数据一般都是如下图1所示的格式,那么我们如何在页面上展现出图2的效果呢?

 

(图1:原始表) 

 

(图2:页面效果图) 

       其实就普通树形来说,IDParentID这两个字段是少不了的。 

 

 (图3:数据效果图)

 

逻辑分析

1.         使用字符串分割法把一条记录的pagepath字段进行分解成我们需要的字符串,但是这里的分割有一点点不一样,那就是我们需要把前面的字符串也一起返回;

2.         之后我们就可以对这一段段的字符串进行逻辑处理,也就是进行树形结构的组建;

a)        我们先来判断@Temppath这新分割出来的字符串是否在表PageUrlTree存在;

b)       如果是第一条数据,那就是根目录:'/'这个时候就需要特殊处理,把它当成一个根节点,手动设置IDParentID值;

c)        如果不是第一条数据,那就找出上一个pagepath值来查找出ID值,再进行整型数值的运算来递增一个新值出来作为新纪录的ID值;

d)       @countBefore@TempPath_Before的设定很有意义,因为这是对ParentID判断的一个变量;

 

技术点

1.         数据库结构树的设计逻辑;

2.         数据库游标的使用;

3.         SQL字符串的分割;

4.         SQL判断一个字符在字符串中出现的次数;

5.         字符串与整数类型之间的转换;

6.         保存了上个ParentPagePath值;

7.         当没有返回值的时候,可以进行@MaxID is null这样的判断

 

四、代码实现

步骤1首先创建一个测试表,这个测试表只包括了pagepath这个字段,等下就会对这个字段进行分析,分解成不同的记录和不同的属性值。 

-- 1,创建测试表
if   exists  ( select   *   from  sysobjects  where  id  =   OBJECT_ID ( ' [temp_url] ' and   OBJECTPROPERTY (id,  ' IsUserTable ' =   1
DROP   TABLE   [ temp_url ]

CREATE   TABLE   [ temp_url ]  (
[ pagepath ]   [ varchar ]   ( 300 NULL )

INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/easyurl/pages/index.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/easyurl/pages/reportContent.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/easyurl/pages/sort_edit.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/performancemonitor/pages/OnlinePerformBySystem.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/performancemonitor/pages/PerformanceContent.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/siteMapManage/siteMapManageEdit.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/warning/pages/ErrorWarning.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/apps/warning/pages/ErrorWarningByPage.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/msg/pages/Error.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/msg/pages/LogQuery.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/msg/pages/success.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/ChangePassword.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/CustomerUserRoles.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/editresource.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/EditRole.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/OnlineUserRolesManager.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/resources.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/Roles.aspx ' )
INSERT   [ temp_url ]  ( [ pagepath ] VALUES  (  ' /Web/contrib/security/pages/Users.aspx ' )

 

步骤2接着创建一个用来保存这个树形的结构表,[ID][ParentID]是少不了的了,[PagePath]是页面路径的字符串,[IsPage]表示这条记录是否是页面,也就是说是否是叶子节点。 

-- 2,创建结果表
SET  ANSI_NULLS  ON
GO
SET  QUOTED_IDENTIFIER  ON
GO
SET  ANSI_PADDING  ON
GO
CREATE   TABLE   [ dbo ] . [ PageUrlTree ] (
    
[ ID ]   [ varchar ] ( 50 ) COLLATE Chinese_PRC_CI_AS  NULL ,
    
[ ParentID ]   [ varchar ] ( 50 ) COLLATE Chinese_PRC_CI_AS  NULL ,
    
[ PagePath ]   [ varchar ] ( 100 ) COLLATE Chinese_PRC_CI_AS  NULL ,
    
[ IsPage ]   [ int ]   NULL   CONSTRAINT   [ DF_PageUrlTree_IsPage ]    DEFAULT  (( 0 ))
ON   [ PRIMARY ]

GO
SET  ANSI_PADDING  OFF

 

步骤3接着创建一个用户函数,[Get_StrArrayStrOfIndex]这个函数是返回一个字符串中第n个分隔符之前的所有字符串,例如:/Web/apps/pages/index.aspx,当执行select [dbo].[Get_StrArrayStrOfIndex]('/Web/apps/pages/index.aspx','/','4'),返回值就是:“/Web/apps/pages/”,这样做就循环对字符串进行处理了。 

-- 3,创建处理函数
--
 =============================================
--
 Author:        <Viajar>
--
 Create date: <2010.09.01>
--
 Description:    <获取字符串的第n个分隔字符串>
--
 =============================================
Create   function   [ dbo ] . [ Get_StrArrayStrOfIndex ]
(
    
@str   varchar ( 50 ),   -- 要分割的字符串
     @split   varchar ( 10 ),   -- 分隔符号
     @index   int   -- 取第几个元素
)
returns   varchar ( 50 )
as
begin
  
declare   @location   int
  
declare   @start   int
  
declare   @next   int
  
declare   @seed   int
  
set   @str = ltrim ( rtrim ( @str ))
  
set   @start = 1
  
set   @next = 1
  
set   @seed = len ( @split )
  
  
set   @location = charindex ( @split , @str )
  
while   @location <> 0   and   @index > @next
  
begin
    
set   @start = @location + @seed
    
set   @location = charindex ( @split , @str , @start )
    
set   @next = @next + 1
  
end
  
if   @location   = 0   select   @location   = len ( @str ) + 1  

  
return   substring ( @str , 0 , @location + 1 )
end

 

  步骤4接着创建一个存储过程,[sp_CreatePagePathTree]这个存储过程是对这个方案的整个逻辑进行处理。 

-- 4,处理的存储过程
SET  ANSI_NULLS  ON
GO
SET  QUOTED_IDENTIFIER  ON
GO
--  =============================================
--
 Author:        <Viajar>
--
 Create date: <2010.09.15>
--
 Description:    <创建站点树形结构>
--
 Tips:        <读取PageURL表,生成数据到PageUrlTree表>
--
 =============================================
CREATE   PROCEDURE  sp_CreatePagePathTree 

AS
BEGIN

    
-- 清空记录
     truncate    table  PageUrlTree

    
-- 生成树
     DECLARE   @TempPath_Before   varchar ( 100 )
    
DECLARE   @TempPath   varchar ( 100 )
    
DECLARE   @pagepath   varchar ( 50 )
    
DECLARE   @itemCur   CURSOR
    
SET   @itemCur   =   CURSOR   FOR  
        
SELECT  pagepath  FROM  temp_url

    
OPEN   @itemCur
    
FETCH   NEXT   FROM   @itemCur   INTO   @pagepath
    
WHILE   @@FETCH_STATUS = 0
    
BEGIN
        
-- 逻辑处理
         DECLARE   @Word   NVARCHAR ( 2 )
        
DECLARE   @WordAll   NVARCHAR ( 50 )
        
DECLARE   @count   int  
        
DECLARE   @countBefore   int  
        
DECLARE   @i   int
        
DECLARE   @ID   VARCHAR ( 50
        
DECLARE   @ParentID   VARCHAR ( 50 )
        
DECLARE   @MaxID   VARCHAR ( 50 )
        
DECLARE   @SubID   int
        
DECLARE   @IsPage   int
        
set   @IsPage   =   0
        
set   @i   = 1  
        
set   @Word   =   ' / '
        
set   @WordAll   =   @pagepath
        
select   @countBefore   =   len ( replace ( @WordAll , @Word , @Word + ' _ ' )) - len ( @WordAll ) + 1
        
select   @count   =   len ( replace ( @WordAll , @Word , @Word + ' _ ' )) - len ( @WordAll ) + 1

        
select   @TempPath_Before   =  dbo. [ Get_StrArrayStrOfIndex ] ( @pagepath , ' / ' , 1 )

        
WHILE   @count > 0
        
begin
            
select   @Temppath   =  dbo. [ Get_StrArrayStrOfIndex ] ( @pagepath , ' / ' , @i )
            
print   ' @Temppath: '   + @Temppath
            
-- 不存在
             if   not   exists  ( select  ID  from  PageUrlTree  where  PagePath  =   @Temppath )
            
begin
                
select   @ParentID   =  ID  from  PageUrlTree  where  PagePath  =   @TempPath_Before
                
print   ' @ParentID: ' + @ParentID
                
if ( @ParentID   <>   '' )
                
begin
                    
select   @MaxID   =   max (ID)  from  PageUrlTree  where  ParentID  =   @ParentID   and  PagePath  like   @TempPath_Before + ' % '
                    
if  ( @MaxID   is   null )
                        
set   @SubID   =   100
                    
else
                        
select   @SubID   =   convert ( int , substring ( @MaxID , len ( @MaxID ) - 2 , len ( @MaxID ))) + 1

                    
-- 如果是.的话就表示是页面
                     if  ( charindex ( ' . ' , @TempPath ) > 0 )
                        
set   @IsPage   = 1
                    
INSERT  PageUrlTree  VALUES ( @ParentID   +   convert ( varchar ( 10 ), @SubID ), @ParentID , @Temppath , @IsPage )
                
end  
                
else
                    
INSERT  PageUrlTree  VALUES ( ' 100 ' , ' 0 ' , @Temppath , @IsPage ) -- 根节点
             end
        
            
set   @i   =   @i   + 1
            
set   @countBefore   =   @count
            
set   @count   =   @count - 1
            
set   @TempPath_Before   =   @TempPath
        
end

        
FETCH   NEXT   FROM   @itemCur   INTO   @pagepath
    
END  

    
CLOSE   @itemCur
    
DEALLOCATE   @itemCur

END
GO

 

五、总结

其中这个完全可以使用程序代码来解决,但是既然用了SQL,那就把这个过程记录下来吧,希望对其它人有帮助吧。 

 

-------------------华丽分割线-------------------

作者: 听风吹雨
版权:本文版权归作者和博客园共有
转载:欢迎转载,不过记得留下买路钱
格言:不喜欢是因为你不会 && 因为会所以喜欢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值