使用递归公用表表达式在SQL Server中使用T-SQL查找相关表

时间:2017-10-03 11:48:49

标签: sql sql-server tsql common-table-expression

我正在尝试编写一个递归公用表表达式,该表达式通过外键创建所有表的树结构,但是我会遇到具有多对多关系的表。任何人都可以为我解决这个问题吗? / p>

第一个选择是获取所有外键。第二种是递归地将它们与父/子连接相关联。递归在表2停止,即使有表3的链接。有人可以帮忙吗? (在编辑中添加了表格)。

 CREATE TABLE [db].[table_one]
(
    [table_one_id] int NOT NULL PRIMARY KEY, [one_column_one] int, [one_column_two] varchar(8), [one_column_three] varchar(7)
)

CREATE TABLE [db].[table_two]
(
    [table_two_id] int NOT NULL PRIMARY KEY, [table_one_id] int, [table_three_id] int, [two_column_one] int, [two_column_two] varchar(8), [two_column_three] varchar(7)
)

CREATE TABLE [db].[table_three]
(
    [table_three_id] int NOT NULL PRIMARY KEY, [table_four_id] int, [column_one] int, [column_two] varchar(8), [column_three] varchar(7)
)

CREATE TABLE [db].[table_four]
(
    [table_four_id] int NOT NULL PRIMARY KEY, [column_one] int, [column_two] varchar(8), [column_three] varchar(7)
)

ALTER TABLE [db].[table_two] ADD CONSTRAINT [fk_table_one_table_two] FOREIGN KEY ([table_one_id]) REFERENCES [db].[table_one] ([table_one_id])
ALTER TABLE [db].[table_two] ADD CONSTRAINT [fk_table_three_table_two] FOREIGN KEY ([table_three_id]) REFERENCES [db].[table_three] ([table_three_id])
ALTER TABLE [db].[table_three] ADD CONSTRAINT [fk_table_four_table_three] FOREIGN KEY ([table_four_id]) REFERENCES [db].[table_four] ([table_four_id])

DECLARE @table_name as varchar(25) = 'table_one';
DECLARE @false as Bit = 0, @true as Bit = 1;

with relationship_tables as 
(
    select    s1.name as child_schema,        
             o1.Name as child_table,        
             s2.name as parent_schema,    
             o2.Name as parent_table    
    from sys.foreign_keys fk    
    inner join sys.objects o1 on fk.parent_object_id = o1.object_id    
    inner join sys.schemas s1 on o1.schema_id = s1.schema_id    
    inner join sys.objects o2 on fk.referenced_object_id = o2.object_id    
    inner join sys.schemas s2 on o2.schema_id = s2.schema_id    
    where not (s1.name = s2.name and o1.name = o2.name) /*exclude self-referencing*/
)
,
hierarchy AS 
(        
       SELECT rt.parent_schema, 
              rt.parent_table, 
              s.name as child_schema,
              t.name as child_table, 
              CONVERT(VARCHAR(4096), '>' + CONVERT(VARCHAR(50), t.name ) + '>' ) as path, 
              @false as Loop, 0 AS Level
        FROM    (select * from sys.tables where name <> 'sysdiagrams') t    
        INNER JOIN sys.schemas s on t.schema_id = s.schema_id    
        LEFT OUTER JOIN relationship_tables rt ON s.name = rt.child_schema AND t.name = rt.child_schema    
        WHERE rt.parent_schema IS NULL
       AND t.name LIKE '%' + @table_name + '%'
        UNION    ALL
       SELECT  rt.parent_schema, 
              rt.parent_table, 
              rt.child_schema,
              rt.child_table,
              CONVERT(VARCHAR(4096), path + CONVERT(VARCHAR(50), rt.child_table ) + '>' ), 
              CASE WHEN CHARINDEX( '>' + CONVERT(VARCHAR(50), rt.child_table ) + '>', PATH) = 0 THEN @false ELSE @true END, 
              hr.Level + 1
        FROM    relationship_tables rt   
        INNER JOIN hierarchy hr ON rt.parent_schema = hr.child_schema AND rt.parent_table = hr.child_table
       WHERE hr.Loop = 0 
)
select parent_table, child_table, path, level from hierarchy
order by level

这是另一项不起作用的尝试:

declare @Objects_In_Objects table
(
  ObjectID varchar(25), 
  ParentObjectId varchar(25)
)

declare @Objects table
(
  ObjectId varchar(25), 
  Name varchar(50)
)

insert into @Objects values
('db.table_one', 'Start table'),  
('db.table_two', 'Many to Many'),  
('db.table_three', 'Related Table'),  
('db.table_four', 'Related Table')

--ObjectID--ParentObjectId
insert into @Objects_In_Objects values
('db.table_one', 'db.table_two'),
('db.table_three', 'db.table_two'),
('db.table_four', 'db.table_three')

DECLARE @ObjectId varchar(25)
SET @ObjectId = 'db.table_one';

;WITH Tree AS
(
   SELECT A.ObjectID, A.Name, o.ParentObjectID, 1 AS 'Level'
   FROM @Objects A
   INNER JOIN @Objects_In_Objects o ON A.ObjectID = o.ParentObjectID OR A.ObjectId = o.ObjectID
   WHERE A.ObjectId = @ObjectId          -- use the A.ObjectId here

   UNION ALL

   SELECT A2.ObjectID, A2.Name, B.ParentObjectID, t.Level + 1 AS 'Level'
   FROM Tree t 
   INNER JOIN @Objects_In_Objects B ON B.ParentObjectID = t.ObjectID
   INNER JOIN @Objects A2 ON A2.ObjectId = B.ObjectId        
)
SELECT *
FROM Tree
INNER JOIN @Objects ar on tree.ObjectId = ar.ObjectId

0 个答案:

没有答案