zoukankan      html  css  js  c++  java
  • 简单实用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]  (300NULL)

    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,那就把这个过程记录下来吧,希望对其它人有帮助吧。 

     

    作者:听风吹雨
    出处: http://www.cnblogs.com/gaizai/
    邮箱:gaizai@126.com
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,必须保留原文链接
    格言:不喜欢是因为不会 && 因为会所以喜欢

  • 相关阅读:
    Windows下MemCache多端口安装配置
    PL/SQL Developer 9.x 注册码
    SQL Server 表变量和临时表的区别
    SQL 存储过程入门(事务)
    把存储过程结果集SELECT INTO到临时表
    在T-SQL语句中访问远程数据库(openrowset/opendatasource/openquery)
    解决SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT'OpenRowset/OpenDatasource' 的访问的方法
    C#性能优化实践
    sql server 存储过程中使用变量表,临时表的分析(续)
    Request.Url.Port 获取不到正确的端口号
  • 原文地址:https://www.cnblogs.com/gaizai/p/1828460.html
Copyright © 2011-2022 走看看