【问题标题】:SQL Building Pathway using With Union in SQL Server在 SQL Server 中使用 With Union 构建 SQL 路径
【发布时间】:2012-05-20 19:38:00
【问题描述】:

这是 SQL Server 问题

我有一组类别,它们的关系导致嵌套类别。

我想建立一个途径来保持关系并建立 SEF 网址。这是我正在寻找的内容:

Category table: 
ID, Name
1, Root
2, Cat1
3, Cat2
4, Cat1.1
5, Cat1.2
6, Cat2.1
7, Cat2,2

CategoryChild table: ParentCategoryID, ChildCategoryID
1, 2
1, 3
2, 4
2, 5
3, 6
3, 7

这是一个无限的嵌套结构。这是我正在做的事情(我知道它错了,但想要这样的东西):

WITH  MenuItems
    AS (

        SELECT  

        CAST((ItemPath) AS VARCHAR(1000)) AS 'ItemPath',
        CategoryID, Category, ChildID
        FROM    #Mapping
        WHERE   CategoryID = 1
        UNION ALL
        SELECT  
                CAST((items.ItemPath + '-/' + MenuItem.Category) AS VARCHAR(1000)) AS 'ItemPath',
                MenuItem.CategoryID, MenuItem.Category, MenuItem.ChildID
        FROM     #Mapping AS MenuItem
                JOIN MenuItems AS items
                  ON items.ChildID = MenuItem.CategoryID 
       ) 
select * from MenuItems

它给了我这样的东西:

根--------|1---|根---|2 根--------|1---|根---|3 根/Cat2---|3---|Cat2---|6 根/Cat2---|3---|Cat2---|7 根/Cat1---|2---|Cat1---|4 根/Cat1---|2---|Cat1---|5

所以理想的路径应该是这样的:

根/父/子(等等)!

【问题讨论】:

  • 您忘记了 RECURSIVE 关键字?
  • 您使用的是什么数据库?如果您使用的是 SQL Server,则需要递归 CTE。如果您使用的是 Oracle,则需要使用路径连接。

标签: sql sql-server recursion


【解决方案1】:

我不确定这是否是您要查找的内容,但我过去曾使用过递归 cte,因此这可能有助于构建项目路径。

注意:我已包含附加信息,例如每个项目的 Root Id 和 Level,以便您可以更改输出的顺序。

declare @Category table (Id int, Name varchar(10))
insert into @Category values (1, 'Root'),(2, 'Cat1'), (3, 'Cat2'), (4, 'Cat1.1'), (5, 'Cat1.2'), (6, 'Cat2.1'), (7, 'Cat2.2')

declare @CategoryChild table (ParentCategoryID int, ChildCategoryID int)
insert into @CategoryChild values (1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)

;with cte as 
(
    -- root part
    select 
        ccParent.ChildCategoryID Id,
        ccParent.ParentCategoryID ParentId,
        c.Name Name,
        CAST(parentCategory.Name + '/' + c.Name as varchar(1000)) as Path,
        ccParent.ChildCategoryID Root,
        0 as Level
    from
        @CategoryChild ccParent
    inner join
        @Category c on c.Id = ccParent.ChildCategoryID
    inner join
        @Category parentCategory on parentCategory.Id = ccParent.ParentCategoryID
    where
        ccParent.ParentCategoryID = 1

    union all

    -- recursive part
    select
        ccChild.ChildCategoryID Id,
        ccChild.ParentCategoryID ParentId,
        c.Name Name,
        CAST((cte.Path + '/' + c.Name) as varchar(1000)) as Path,
        cte.Root Root,
        cte.Level + 1 as Level
    from
        @CategoryChild ccChild
    inner join
        @Category c on c.Id = ccChild.ChildCategoryID
    inner join
        cte on cte.Id = ccChild.ParentCategoryID
)
select cte.Path 
from cte 
order by cte.Root, cte.Level

在我的环境中运行上述代码会得到以下结果

Root/Cat1
Root/Cat1/Cat1.1
Root/Cat1/Cat1.2
Root/Cat2
Root/Cat2/Cat2.1
Root/Cat2/Cat2.2

如果您希望将 Root 类别作为独立项包含在结果集中,则可以将 cte 的第一部分更改为对根项的选择进行硬编码。

;with cte as 
(
    -- root part
    select 
        c.Id Id,
        null ParentId,
        c.Name Name,
        CAST(c.Name as varchar(1000)) as Path,
        c.Id Root,
        0 as Level
    from
        @Category c
    where 
        c.Name = 'Root'

    union all

    ... same as before

给予关注

Root
Root/Cat1
Root/Cat1/Cat1.1
Root/Cat1/Cat1.2
Root/Cat2
Root/Cat2/Cat2.1
Root/Cat2/Cat2.2

【讨论】:

  • 嗯,所以用'Null ParentID'硬编码根猫会出错,告诉ParentID的列类型在'union all'中不匹配,所以我只是将'CAST(0 as bigint)作为ParentID' 所以它工作正常。 (我对 ID 列使用 BigInt 类型),所以在做这些事情时必须牢记列类型。祝你好运!
猜你喜欢
  • 2018-01-02
  • 2023-01-26
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-03
  • 1970-01-01
  • 2020-04-28
相关资源
最近更新 更多