简体   繁体   English

使用T-SQL筛选层次结构数据的最佳方法?

[英]Best way to filter hierarchical data using T-SQL?

Table1 has a list of items. 表1列出了项目。 Table2 has a list of groups the items can be associated with. Table2列出了可以与项目关联的组。 Table3 is a cross-reference between 1 and 2. 表3是1到2之间的交叉引用。

The groups in table 2 are set up in hierarchical fashion. 表2中的组以分层方式设置。

Key    ParentKey    Name
1      NULL         TopGroup1
2      NULL         TopGroup2
3      1            MiddleGroup1
4      2            MiddleGroup2
5      3            NextGroup1
6      4            NextGroup1
7      2            MiddleGroup3

I want to be able to select from Table1 filtered by Table3. 我希望能够从由Table3过滤的Table1中进行选择。
Select Items from Table1 Where Table3.ParentKey NOT '2' or any of it's descendants . 从Table1中选择项目,其中Table3.ParentKey不是'2' 或其任何后代

From another post here on stack overflow I've been able to use CTE to identify the hierarchy. 在堆栈溢出的另一篇文章中我已经能够使用CTE来识别层次结构。

WITH Parent AS
(
    SELECT
        table2.Key,
        cast(table2.Key as varchar(128))  AS Path
    FROM
        table2
    WHERE
        table2.ParentKey IS NULL

   UNION ALL

    SELECT
        TH.Key,
        CONVERT(varchar(128), Parent.Path + ',' + CONVERT(varchar(128),TH.Key)) AS Path
    FROM
        table2 TH
    INNER JOIN
        Parent
    ON
        Parent.Key = TH.ParentKey
)
SELECT * FROM Parent

I guess this is really a two part question. 我想这确实是一个两部分的问题。

  1. How do you filter the above? 您如何过滤以上内容? For example, return all groups where TopGroup1 isn't in the lineage. 例如,返回不在TopGroup1中的所有组。
  2. How would I apply that to filtering results in the cross-referenced table1. 我如何将其应用于交叉引用表1中的过滤结果。

There is a whole book on this topic, see: ' Joe Celko's Trees and Hierarchies in SQL for Smarties ' 有一本关于该主题的整本书,请参见:' 聪明人的SQL中Joe Celko的树和层次结构 '

Personally, when I had to solve this problem, I used a temp table to unroll the hierarchy and then selected stuff from the temp table. 就个人而言,当我必须解决此问题时,我使用了一个临时表来展开层次结构,然后从临时表中选择内容。 Essentially you can build up another layer in the temp table in a single query, usually hierarchies are only 5-10 layers deep, so you can unroll it in 5 to 10 queries. 本质上,您可以在单个查询中在临时表中建立另一层,通常层次仅深5-10层,因此您可以在5到10个查询中展开它。

Try this 尝试这个

-- Table1 (ItemKey as PK, rest of the columns)
-- Table2 (as you defined with Key as PK)
-- Table3 (ItemKey  as FK referencing Table1(ItemKey), 
--         GroupKey as FK referencing Table2(Key))

Declare @Exclude int
Set @Exclude = 2          
;WITH Groups AS     -- returns keys of groups where key is not equal
(                   -- to @Exclude or any of his descendants
   SELECT t.Key
     FROM table2 t
    WHERE t.ParentKey IS NULL
      and t.Key <> @Exclude
   UNION ALL
   SELECT th.Key,
     FROM table2 th
    INNER JOIN Groups g ON g.Key = th.ParentKey
    Where th.Key <> @Exclude
)
SELECT t1.* 
  FROM Table1 t1
 WHERE t1.key in (Select t3.ItemKey 
                    From table3 t3 
                   Inner Join Groups g2 
                      on t3.GroupKey = g2.Key
                 )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM