SQLServer: How to sort table names ordered by their foreign key dependency

前端 未结 4 1419
后悔当初
后悔当初 2020-12-23 22:39

The following SQL separates tables according to their relationship. The problem is with the tables that sort under the 3000 series. Tables that are part of foreign keys and

4条回答
  •  Happy的楠姐
    2020-12-23 22:44

    You can use an iterative algorithm, which is probably less convoluted than a CTE. Here's an example that sorts according to depth:

    declare @level int      -- Current depth
           ,@count int      
    
    -- Step 1: Start with tables that have no FK dependencies
    --  
    if object_id ('tempdb..#Tables') is not null
        drop table #Tables
    
    select s.name + '.' + t.name  as TableName
          ,t.object_id            as TableID
          ,0                      as Ordinal
      into #Tables
      from sys.tables t
      join sys.schemas s
        on t.schema_id = s.schema_id
     where not exists
           (select 1
              from sys.foreign_keys f
             where f.parent_object_id = t.object_id)
    
    set @count = @@rowcount         
    set @level = 0
    
    
    -- Step 2: For a given depth this finds tables joined to 
    -- tables at this given depth.  A table can live at multiple 
    -- depths if it has more than one join path into it, so we 
    -- filter these out in step 3 at the end.
    --
    while @count > 0 begin
    
        insert #Tables (
               TableName
              ,TableID
              ,Ordinal
        ) 
        select s.name + '.' + t.name  as TableName
              ,t.object_id            as TableID
              ,@level + 1             as Ordinal
          from sys.tables t
          join sys.schemas s
            on s.schema_id = t.schema_id
         where exists
               (select 1
                  from sys.foreign_keys f
                  join #Tables tt
                    on f.referenced_object_id = tt.TableID
                   and tt.Ordinal = @level
                   and f.parent_object_id = t.object_id
                   and f.parent_object_id != f.referenced_object_id)
                       -- The last line ignores self-joins.  You'll
                       -- need to deal with these separately
    
       set @count = @@rowcount
       set @level = @level + 1
    end
    
    -- Step 3: This filters out the maximum depth an object occurs at
    -- and displays the deepest first.
    --
    select t.Ordinal
          ,t.TableID
          ,t.TableName
      from #Tables t
      join (select TableName     as TableName
                  ,Max (Ordinal) as Ordinal
              from #Tables
             group by TableName) tt
        on t.TableName = tt.TableName
       and t.Ordinal = tt.Ordinal
     order by t.Ordinal desc
    

提交回复
热议问题