如何获得最深层次的分层SQL查询

时间:2012-02-09 21:49:03

标签: sql sql-server hierarchical-data

我正在使用SQLServer 2008。

假设我有一个递归层次结构表,SalesRegion,whit SalesRegionId和ParentSalesRegionId。我需要的是,给定一个特定的SalesRegion(层次结构中的任何位置),检索BOTTOM级别的所有记录。

即: SalesRegion,ParentSalesRegionId

1,null

1-1,1

1-2,1

1-1-1,1-1

1-1-2,1-1

1-2-1,1-2

1-2-2,1-2

1-1-1-1,1-1-1

1-1-1-2,1-1-1

1-1-2-1,1-1-2

1-2-1-1,1-2-1

(在我的表中,我有顺序数字,这个虚线数字只是要清楚)

因此,如果用户输入1-1,我需要使用SalesRegion 1-1-1-1或1-1-1-2或1-1-2-1(而不是1-2)检索al记录-2)。同样,如果用户输入1-1-2-1,我只需要检索1-1-2-1

我有一个CTE查询,可以检索1-1以下的所有内容,但是包含我不想要的行:

WITH SaleLocale_CTE AS (
    SELECT SL.SaleLocaleId, SL.SaleLocaleName, SL.AccountingLocationID, SL.LocaleTypeId, SL.ParentSaleLocaleId, 1 AS Level /*Added as a workaround*/
      FROM SaleLocale SL
     WHERE SL.Deleted = 0
       AND (@SaleLocaleId IS NULL OR SaleLocaleId = @SaleLocaleId)
     UNION ALL
    SELECT SL.SaleLocaleId, SL.SaleLocaleName, SL.AccountingLocationID, SL.LocaleTypeId, SL.ParentSaleLocaleId, Level + 1 AS Level
      FROM SaleLocale SL
           INNER JOIN SaleLocale_CTE SLCTE ON SLCTE.SaleLocaleId = SL.ParentSaleLocaleId
     WHERE SL.Deleted = 0
)
SELECT *
FROM SaleLocale_CTE

提前致谢!

亚历。

4 个答案:

答案 0 :(得分:0)

我找到了一种快速的方法来做到这一点,但我宁愿将答案放在一个查询中。所以,如果你能想到一个,请分享!如果我更喜欢它,我会投票给它作为最佳答案。

我在之前的查询中添加了“级别”列(我将编辑问题以便明确这个答案),并使用它来获取最后一级,然后删除我不需要的那些。

INSERT INTO @SaleLocales
    SELECT *
      FROM SaleLocale_GetChilds(@SaleLocaleId)

SELECT @LowestLevel = MAX(Level)
  FROM @SaleLocales

DELETE @SaleLocales
 WHERE Level <> @LowestLevel

答案 1 :(得分:0)

建立你的职位:

; WITH CTE AS
(
    SELECT *
    FROM SaleLocale_GetChilds(@SaleLocaleId)
)
SELECT
FROM CTE a
JOIN
(
    SELECT MAX(level) AS level
    FROM CTE
) b
    ON a.level = b.level

那里有一些编辑。保持打击......

答案 2 :(得分:0)

你在寻找这样的东西:

declare @SalesRegion as table ( SalesRegion int, ParentSalesRegionId int )
insert into @SalesRegion ( SalesRegion, ParentSalesRegionId ) values
  ( 1, NULL ), ( 2, 1 ), ( 3, 1 ),
  ( 4, 3 ), ( 5, 3 ),
  ( 6, 5 )

; with CTE as (
  -- Get the root(s).
  select SalesRegion, CAST( SalesRegion as varchar(1024) ) as Path
    from @SalesRegion
    where ParentSalesRegionId is NULL
  union all
  -- Add the children one level at a time.
  select SR.SalesRegion, CAST( CTE.Path + '-' + cast( SR.SalesRegion as varchar(10) ) as varchar(1024) )
    from CTE inner join
      @SalesRegion as SR on SR.ParentSalesRegionId = CTE.SalesRegion      
  )
  select *
    from CTE
    where Path like '1-3%'

答案 3 :(得分:0)

我没有在严肃的数据集上试过这个,所以我不确定它会如何表现,但我相信它可以解决你的问题:

WITH SaleLocale_CTE AS (
            SELECT SL.SaleLocaleId, SL.SaleLocaleName, SL.AccountingLocationID, SL.LocaleTypeId, SL.ParentSaleLocaleId, CASE WHEN EXISTS (SELECT 1 FROM SaleLocal SL2 WHERE SL2.ParentSaleLocaleId = SL.SaleLocaleID) THEN 1 ELSE 0 END as HasChildren
              FROM SaleLocale SL
             WHERE SL.Deleted = 0
               AND (@SaleLocaleId IS NULL OR SaleLocaleId = @SaleLocaleId)
             UNION ALL
            SELECT SL.SaleLocaleId, SL.SaleLocaleName, SL.AccountingLocationID, SL.LocaleTypeId, SL.ParentSaleLocaleId, CASE WHEN EXISTS (SELECT 1 FROM SaleLocal SL2 WHERE SL2.ParentSaleLocaleId = SL.SaleLocaleID) THEN 1 ELSE 0 END as HasChildren
              FROM SaleLocale SL
                   INNER JOIN SaleLocale_CTE SLCTE ON SLCTE.SaleLocaleId = SL.ParentSaleLocaleId
             WHERE SL.Deleted = 0
)
SELECT *
FROM SaleLocale_CTE
WHERE HasChildren = 0