Sql-Server

微軟SQL。帶條件的樹結構獲取

  • May 28, 2019

我需要製作一個樹形結構

表:

create table Dirs
(
   Id           uniqueidentifier primary key not null default (newid()),
   Name         nvarchar(30)                 not null,
   CreatedDate  datetime                     not null default getdate(),
   ModifiedDate datetime                     not null default getdate(),
   IsCollapsed  bit                                   default dbo.randbit(newid()),
   ParentId     uniqueidentifier                      default null
)

我想從特定節點獲取所有子節點(例如通過 id),但過濾掉關閉目錄的子節點,將它們本身保留在輸出中?

例如給定結構

root
  - Dir1 (v)
     -Dir2 (v)
        -Dir3(x)
           -Dir4(v)
              -Dir5(v)

其中x- 表示目錄已折疊,v- 表示目錄已展開。

預期輸出為:

Dir1
Dir2
Dir3

我寫了這樣的查詢:

create procedure GetNodes @parentId uniqueidentifier = null
as
begin
   with dirsrec as (
       select *
       from Dirs
       where Id = @parentId
       union all
       (
           select d.Id, d.Name, d.CreatedDate, d.ModifiedDate, d.IsCollapsed, j.id as ParentId
           from Dirs d
                    join dirsrec as j on d.ParentId = j.Id
           where d.IsCollapsed = 'false'
       )
   ), 
        dirsec2 as (
            select *
            from Dirs
            where Id = @parentId
            union all
            (
                select d.Id, d.Name, d.CreatedDate, d.ModifiedDate, d.IsCollapsed, j.id as ParentId
                from Dirs d
                         join dirsrec as j on d.ParentId = j.Id
                where d.IsCollapsed = 'true'
            )
        )
   select *
   from dirsrec
   union
   select *
   from dirsec2
end

它使用2個遞歸。第一個是從給定的節點中獲取所有打開的節點,第二個是獲取所有關閉的節點,然後輸出得到區分

它可以工作,但我不喜歡使用幾乎相同的程式碼的 2 個單獨的查詢。我想它可能會做得更好

我試圖產生副作用(將union all(子查詢中的折疊節點插入臨時表,然後將其與最終結果合併,但看起來 sql 不允許我們在子查詢中創建一些邏輯)

WITH cte AS ( SELECT * 
             FROM tree 
             WHERE id = @starting_node
                 UNION ALL
             SELECT tree.* 
             FROM tree, cte
             WHERE tree.parent_id = cte.id
               AND cte.IsCollapsed = 'expanded' -- if collapsed then stop
           ) 

引用自:https://dba.stackexchange.com/questions/239189