如何获取关系数据库中2个随机表之间的关系

时间:2018-03-23 22:23:07

标签: sql sql-server tsql

我的要求是加入表A和表D.我知道其间有表B和C,它们有PK和FK关系。我想要一个查询来了解表B和C以及关系中涉及的键。我需要知道整个数据库。数据库图将给我关系,但我没有权限查看图表。而且,我需要查找每组表。这就是我试图编写一个为我完成工作的查询的原因。

简而言之,如果我在查询中提供表A和表D,那么查询应该为我提供必要的列(在我们的例子中为B.id2,C.id3)来加入A和D.

SELECT A.*, D.* FROM A Join B on A.id1 = B.id2 Join C on B.id2 = C.id3 Join D on C.id3 = D.id4

提前致谢。

enter image description here

3 个答案:

答案 0 :(得分:2)

我拉起了我在工作中写的那个;看起来我实际上并没有打扰CTE(因为他们是屁股恕我直言的皇家痛苦)。它有点冗长,因为它只是我从proc中删除的代码。我的版本最初没有包含列,但我添加了它们。我只是将它们连接起来就像它们是ON子句一样,但你可以调整你喜欢的方式。

use AdventureWorks2014
go

declare 
    @BaseTable nvarchar(128) = 'SalesPerson',
    @BaseTableSchema nvarchar(128) = 'Sales'

declare
    @Depth int = 0,
    @RowCount int,
    @Ident int

declare @KeyHierarchy table
(
    Depth int,
    ReferencingTableSchema nvarchar(128),
    ReferencingTableName nvarchar(128),
    ReferencingObjectId int,
    ReferencingTableNameFull as quotename(ReferencingTableSchema) + '.' + quotename(ReferencingTableName),
    ReferencedTableSchema nvarchar(128),
    ReferencedTableName nvarchar(128),
    ReferencedObjectId int,
    ReferencedTableNameFull as quotename(ReferencedTableSchema) + '.' + quotename(ReferencedTableName),
    MatchingColumns nvarchar(max)

    primary key clustered (ReferencingTableSchema, ReferencingTableName)
)

insert into @KeyHierarchy
(
    Depth,
    ReferencingTableSchema,
    ReferencingTableName,
    ReferencingObjectId
)
select
    Depth = @Depth,
    ReferencingTableSchema = @BaseTableSchema,
    ReferencingTableName = @BaseTable,
    ReferencingObjectId = object_id(@BaseTableSchema + '.' + @BaseTable)

select @RowCount = 1

while @RowCount > 0
begin

    insert into @KeyHierarchy
    (
        Depth,
        ReferencedTableSchema,
        ReferencedTableName,
        ReferencedObjectId,
        ReferencingTableSchema,
        ReferencingTableName,
        ReferencingObjectId,
    MatchingColumns
    )
    select distinct
        Depth = @Depth + 1,
        ReferencedTableSchema = object_schema_name(f.referenced_object_id),
        ReferencedTableName = object_name(f.referenced_object_id),
        ReferencedObjectId = f.referenced_object_id,
        ReferencingTableSchema = object_schema_name(f.parent_object_id),
        ReferencingTableName = object_name(f.parent_object_id),
        ReferencingObjectId = f.parent_object_id,
        MatchingColumns = stuff
            (
                (
                    select 
                        concat
                        (
                            ' and parent.', 
                            quotename(col_name(c.parent_object_id, c.parent_column_id)), 
                            ' = ',
                            'referenced.',
                            quotename(col_name(c.referenced_object_id, c.referenced_column_id))
                        )
                    from sys.foreign_key_columns c
                    where f.object_id = c.constraint_object_id
                    order by c.constraint_column_id
                    for xml path(''), type
                ).value('.', 'nvarchar(max)'), 1, 4, ''
            )
    from @KeyHierarchy k
    inner join sys.foreign_keys f
        on f.referenced_object_id = k.ReferencingObjectId
            and f.parent_object_id not in (select ReferencingObjectId from @KeyHierarchy where Depth < @Depth + 1)
    where k.Depth = @Depth

    select
        @RowCount = @@RowCount,
        @Depth += 1

end

select 
    BaseTable = @BaseTable,
    ReferencingTableNameFull,
    ReferencedTableNameFull,
    MatchingColumns,
    Depth
from @KeyHierarchy
order by Depth, ReferencingTableNameFull

答案 1 :(得分:0)

这有一些问题,但它是一个开始

select t.name [t_name], c.name [c_name], f.* 
from sys.foreign_keys f  
join sys.tables t
  on f.parent_object_id = t.object_id 
 and f.type = 'F'
left join sys.columns c
  on c.object_id = f.referenced_object_id 
 and c.system_type_id = 56

答案 2 :(得分:0)

你可以从这个出发点摆弄:

with
  ForeignKeys as (
    -- All foreign keys with their associated tables and columns.
    select fk.name as ConstraintName, fk.object_id as ContraintObjectId,
      pt.name as ParentTable, pt.object_id as ParentTableObjectId, pc.name as ParentColumn, pc.column_id as ParentColumnId,
      ft.name as ForeignTable, ft.object_id as ForeignTableObjectId, fc.name as ForeignColumn, fc.column_id as ForeignColumnId
      from sys.foreign_keys as fk inner join
        sys.foreign_key_columns as fkc on fkc.constraint_object_id = fk.object_id inner join
        sys.tables as pt on pt.object_id = fkc.parent_object_id inner join
        sys.columns as pc on pc.object_id = pt.object_id and pc.column_id = fkc.parent_column_id inner join
        sys.tables as ft on ft.object_id = fkc.referenced_object_id inner join
        sys.columns as fc on fc.object_id = ft.object_id and fc.column_id = fkc.referenced_column_id ),
  RelatedTables as (
    -- All ordered pairs of directly related tables.
    select distinct ParentTable, ParentTableObjectId, ForeignTable, ForeignTableObjectId
      from ForeignKeys ),
  RelatedTablesHierarchy as (
    -- Hierarchy of related tables.
    -- Start from each distinct table that has a foreign key relation ...
    select ParentTable, ParentTableObjectId, ForeignTable, ForeignTableObjectId,
      Cast( ParentTable + '»' + ForeignTable as NVarChar(4000) ) as Path
      from RelatedTables
    union all
    -- ... and add any other table to which the foreign table is related.
    select RTH.ParentTable, RTH.ParentTableObjectId, RT.ForeignTable, RT.ForeignTableObjectId,
      Cast( Path + '»' + RT.ForeignTable as NVarChar(4000) )
      from RelatedTablesHierarchy as RTH inner join
        RelatedTables as RT on RT.ParentTableObjectId = RTH.ForeignTableObjectId
      -- NB: Avoid getting caught in reference loops.
      where '»' + Path + '»' not like '%»' + RT.ForeignTable + '»%'
      )
    -- Output the results with   Path   made a little easier to read.
    select Replace( Path, '»', ' » ' ) as Path, ParentTable, ParentTableObjectId, ForeignTable, ForeignTableObjectId
      from RelatedTablesHierarchy
      order by Path;

初始查询肯定带有一些额外的包袱,但您需要它来确定连接所需的表名和列名。 (提示:在将对象名称组合到语句中时使用QuoteName()。)

注意:公共表表达式对参考循环有抵抗力,例如:具有外键引用自身的表以及涉及多个表的较长循环。