【问题标题】:Know relationships between all the tables of database in SQL Server了解 SQL Server 中所有数据库表之间的关系
【发布时间】:2011-12-27 00:10:03
【问题描述】:

我希望所有人都知道我的数据库中的表是如何相互关联的(即 PK/FK/UK),因此我在 SQL Server 中创建了我所有表的数据库图。创建的图表不易阅读,必须滚动(水平滚动,有时垂直滚动)才能看到另一端的表格。

简而言之,当涉及到了解许多表之间的关系时,SQL 的数据库图对 UI 不友好。

我的(简单)问题:是否有类似数据库图的东西可以做数据库图所做的但以“好”的方式?

【问题讨论】:

标签: sql sql-server database tsql


【解决方案1】:

Microsoft Visio 可能是我遇到过的最好的,尽管据我所知它不会根据您的关系自动生成。

编辑:在 Visio 中试试这个,可以给你你需要的东西 http://office.microsoft.com/en-us/visio-help/reverse-engineering-an-existing-database-HA001182257.aspx

【讨论】:

  • 是的,Visio 不会自动生成关系。另外,visio可以连接db吗?
  • 哦,是的!反向英格。我过去做了。谢谢你再次提醒。
【解决方案2】:

或者你可以看看schemacrawler

【讨论】:

    【解决方案3】:

    有时,文本表示也可能会有所帮助;通过对系统目录视图的此查询,您可以获得所有 FK 关系的列表以及如何链接两个表(以及它们操作的列)。

    SELECT
        fk.name 'FK Name',
        tp.name 'Parent table',
        cp.name, cp.column_id,
        tr.name 'Refrenced table',
        cr.name, cr.column_id
    FROM 
        sys.foreign_keys fk
    INNER JOIN 
        sys.tables tp ON fk.parent_object_id = tp.object_id
    INNER JOIN 
        sys.tables tr ON fk.referenced_object_id = tr.object_id
    INNER JOIN 
        sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
    INNER JOIN 
        sys.columns cp ON fkc.parent_column_id = cp.column_id AND fkc.parent_object_id = cp.object_id
    INNER JOIN 
        sys.columns cr ON fkc.referenced_column_id = cr.column_id AND fkc.referenced_object_id = cr.object_id
    ORDER BY
        tp.name, cp.column_id
    

    将其转储到 Excel 中,您可以根据父表、引用表或其他任何内容进行切片和切块。

    我发现视觉指南很有帮助 - 但有时,文本文档也一样好(甚至更好) - 只是我的 2 美分.....

    【讨论】:

    • 那个脚本真的很有用。在需要查看所有表的关系时很有帮助
    • 是否兼容 sql server 2k?它也找不到“sys.foreign_keys”和其他表。
    • @Pratik:这仅适用于 SQL Server 2005 和更新版本
    • @marc_s - 好的,谢谢,但是你能推荐一些关于 sql server 2000 的东西吗?
    • @Marc_S 非常感谢!这太棒了!
    【解决方案4】:

    使用 INFORMATION_SCHEMA 检索相同数据的另一种方式

    SQL Server 中包含的信息架构视图符合 INFORMATION_SCHEMA 的 ISO 标准定义。

    sqlauthority way

    SELECT
    K_Table = FK.TABLE_NAME,
    FK_Column = CU.COLUMN_NAME,
    PK_Table = PK.TABLE_NAME,
    PK_Column = PT.COLUMN_NAME,
    Constraint_Name = C.CONSTRAINT_NAME
    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
    INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
    INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
    INNER JOIN (
    SELECT i1.TABLE_NAME, i2.COLUMN_NAME
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
    WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
    ) PT ON PT.TABLE_NAME = PK.TABLE_NAME
    ---- optional:
    ORDER BY
    1,2,3,4
    WHERE PK.TABLE_NAME='something'WHERE FK.TABLE_NAME='something'
    WHERE PK.TABLE_NAME IN ('one_thing', 'another')
    WHERE FK.TABLE_NAME IN ('one_thing', 'another')
    

    【讨论】:

      【解决方案5】:

      此存储过程将为您提供层次关系树。基于来自 Technet 的 article。它还可以选择为您提供读取或删除所有相关数据的查询。

      IF OBJECT_ID('GetForeignKeyRelations','P') IS NOT NULL 
          DROP PROC GetForeignKeyRelations 
      GO 
      
      CREATE PROC GetForeignKeyRelations 
      @Schemaname Sysname = 'dbo' 
      ,@Tablename Sysname 
      ,@WhereClause NVARCHAR(2000) = '' 
      ,@GenerateDeleteScripts bit  = 0  
      ,@GenerateSelectScripts bit  = 0 
      
      AS 
      
      SET NOCOUNT ON 
      
      DECLARE @fkeytbl TABLE 
      ( 
      ReferencingObjectid        int NULL 
      ,ReferencingSchemaname  Sysname NULL 
      ,ReferencingTablename   Sysname NULL  
      ,ReferencingColumnname  Sysname NULL 
      ,PrimarykeyObjectid     int  NULL 
      ,PrimarykeySchemaname   Sysname NULL 
      ,PrimarykeyTablename    Sysname NULL 
      ,PrimarykeyColumnname   Sysname NULL 
      ,Hierarchy              varchar(max) NULL 
      ,level                  int NULL 
      ,rnk                    varchar(max) NULL 
      ,Processed                bit default 0  NULL 
      ); 
      
      
      
       WITH fkey (ReferencingObjectid,ReferencingSchemaname,ReferencingTablename,ReferencingColumnname 
                  ,PrimarykeyObjectid,PrimarykeySchemaname,PrimarykeyTablename,PrimarykeyColumnname,Hierarchy,level,rnk) 
          AS 
          ( 
              SELECT                   
                                     soc.object_id 
                                    ,scc.name 
                                    ,soc.name 
                                    ,convert(sysname,null) 
                                    ,convert(int,null) 
                                    ,convert(sysname,null) 
                                    ,convert(sysname,null) 
                                    ,convert(sysname,null) 
                                    ,CONVERT(VARCHAR(MAX), scc.name + '.' + soc.name  ) as Hierarchy 
                                    ,0 as level 
                                    ,rnk=convert(varchar(max),soc.object_id) 
              FROM SYS.objects soc 
              JOIN sys.schemas scc 
                ON soc.schema_id = scc.schema_id 
             WHERE scc.name =@Schemaname 
               AND soc.name =@Tablename 
            UNION ALL 
            SELECT                   sop.object_id 
                                    ,scp.name 
                                    ,sop.name 
                                    ,socp.name 
                                    ,soc.object_id 
                                    ,scc.name 
                                    ,soc.name 
                                    ,socc.name 
                                    ,CONVERT(VARCHAR(MAX), f.Hierarchy + ' --> ' + scp.name + '.' + sop.name ) as Hierarchy 
                                    ,f.level+1 as level 
                                    ,rnk=f.rnk + '-' + convert(varchar(max),sop.object_id) 
              FROM SYS.foreign_key_columns sfc 
              JOIN Sys.Objects sop 
                ON sfc.parent_object_id = sop.object_id 
              JOIN SYS.columns socp 
                ON socp.object_id = sop.object_id 
               AND socp.column_id = sfc.parent_column_id 
              JOIN sys.schemas scp 
                ON sop.schema_id = scp.schema_id 
              JOIN SYS.objects soc 
                ON sfc.referenced_object_id = soc.object_id 
              JOIN SYS.columns socc 
                ON socc.object_id = soc.object_id 
               AND socc.column_id = sfc.referenced_column_id 
              JOIN sys.schemas scc 
                ON soc.schema_id = scc.schema_id 
              JOIN fkey f 
                ON f.ReferencingObjectid = sfc.referenced_object_id 
              WHERE ISNULL(f.PrimarykeyObjectid,0) <> f.ReferencingObjectid 
            ) 
      
           INSERT INTO @fkeytbl 
           (ReferencingObjectid,ReferencingSchemaname,ReferencingTablename,ReferencingColumnname 
                  ,PrimarykeyObjectid,PrimarykeySchemaname,PrimarykeyTablename,PrimarykeyColumnname,Hierarchy,level,rnk) 
           SELECT ReferencingObjectid,ReferencingSchemaname,ReferencingTablename,ReferencingColumnname 
                  ,PrimarykeyObjectid,PrimarykeySchemaname,PrimarykeyTablename,PrimarykeyColumnname,Hierarchy,level,rnk 
             FROM fkey 
      
              SELECT F.Relationshiptree 
               FROM 
              ( 
              SELECT DISTINCT Replicate('------',Level) + CASE LEVEL WHEN 0 THEN '' ELSE '>' END +  ReferencingSchemaname + '.' + ReferencingTablename 'Relationshiptree' 
                     ,RNK 
                FROM @fkeytbl 
                ) F 
              ORDER BY F.rnk ASC 
      
      ------------------------------------------------------------------------------------------------------------------------------- 
      -- Generate the Delete / Select script 
      ------------------------------------------------------------------------------------------------------------------------------- 
      
          DECLARE @Sql VARCHAR(MAX) 
          DECLARE @RnkSql VARCHAR(MAX) 
      
          DECLARE @Jointables TABLE 
          ( 
          ID INT IDENTITY 
          ,Object_id int 
          ) 
      
          DECLARE @ProcessTablename SYSNAME 
          DECLARE @ProcessSchemaName SYSNAME 
      
          DECLARE @JoinConditionSQL VARCHAR(MAX) 
          DECLARE @Rnk VARCHAR(MAX) 
          DECLARE @OldTablename SYSNAME 
      
          IF @GenerateDeleteScripts = 1 or @GenerateSelectScripts = 1  
          BEGIN 
      
                WHILE EXISTS ( SELECT 1 
                                 FROM @fkeytbl 
                                WHERE Processed = 0 
                                  AND level > 0 ) 
                BEGIN 
      
                  SELECT @ProcessTablename = '' 
                  SELECT @Sql                 = '' 
                  SELECT @JoinConditionSQL = '' 
                  SELECT @OldTablename     = '' 
      
      
                  SELECT TOP 1 @ProcessTablename = ReferencingTablename 
                        ,@ProcessSchemaName  = ReferencingSchemaname 
                        ,@Rnk = RNK  
                    FROM @fkeytbl 
                   WHERE Processed = 0 
                    AND level > 0  
                   ORDER BY level DESC 
      
      
                  SELECT @RnkSql ='SELECT ' + REPLACE (@rnk,'-',' UNION ALL SELECT ')  
      
                  DELETE FROM @Jointables 
      
                  INSERT INTO @Jointables 
                  EXEC(@RnkSql) 
      
                  IF @GenerateDeleteScripts = 1 
                      SELECT @Sql = 'DELETE [' + @ProcessSchemaName + '].[' + @ProcessTablename + ']' + CHAR(10) + ' FROM [' + @ProcessSchemaName + '].[' + @ProcessTablename + ']' + CHAR(10) 
      
                  IF @GenerateSelectScripts = 1 
                      SELECT @Sql = 'SELECT  [' + @ProcessSchemaName + '].[' + @ProcessTablename + '].*' + CHAR(10) + ' FROM [' + @ProcessSchemaName + '].[' + @ProcessTablename + ']' + CHAR(10) 
      
                  SELECT @JoinConditionSQL = @JoinConditionSQL  
                                                 + CASE  
                                                   WHEN @OldTablename <> f.PrimarykeyTablename THEN  'JOIN ['  + f.PrimarykeySchemaname  + '].[' + f.PrimarykeyTablename + '] ' + CHAR(10) + ' ON ' 
                                                   ELSE ' AND '  
                                                   END 
                                                 + ' ['  + f.PrimarykeySchemaname  + '].[' + f.PrimarykeyTablename + '].[' + f.PrimarykeyColumnname + '] =  ['  + f.ReferencingSchemaname  + '].[' + f.ReferencingTablename + '].[' + f.ReferencingColumnname + ']' + CHAR(10)  
                           , @OldTablename = CASE  
                                               WHEN @OldTablename <> f.PrimarykeyTablename THEN  f.PrimarykeyTablename 
                                               ELSE @OldTablename 
                                               END 
      
                        FROM @fkeytbl f 
                        JOIN @Jointables j 
                          ON f.Referencingobjectid  = j.Object_id 
                       WHERE charindex(f.rnk + '-',@Rnk + '-') <> 0 
                         AND F.level > 0 
                       ORDER BY J.ID DESC 
      
                  SELECT @Sql = @Sql +  @JoinConditionSQL 
      
                  IF LTRIM(RTRIM(@WhereClause)) <> ''  
                      SELECT @Sql = @Sql + ' WHERE (' + @WhereClause + ')' 
      
                  PRINT @SQL 
                  PRINT CHAR(10) 
      
                  UPDATE @fkeytbl 
                     SET Processed = 1 
                   WHERE ReferencingTablename = @ProcessTablename 
                     AND rnk = @Rnk 
      
                END 
      
                IF @GenerateDeleteScripts = 1 
                  SELECT @Sql = 'DELETE FROM [' + @Schemaname + '].[' + @Tablename + ']' 
      
                IF @GenerateSelectScripts = 1 
                  SELECT @Sql = 'SELECT * FROM [' + @Schemaname + '].[' + @Tablename + ']' 
      
                IF LTRIM(RTRIM(@WhereClause)) <> ''  
                      SELECT @Sql = @Sql  + ' WHERE ' + @WhereClause 
      
               PRINT @SQL 
           END 
      
      SET NOCOUNT OFF 
      
      
      go 
      

      【讨论】:

        【解决方案6】:

        我的解决方案基于@marc_s 解决方案,我只是在约束基于多个列的情况下连接列:

        SELECT
           FK.[name] AS ForeignKeyConstraintName
          ,SCHEMA_NAME(FT.schema_id) + '.' + FT.[name] AS ForeignTable
          ,STUFF(ForeignColumns.ForeignColumns, 1, 2, '') AS ForeignColumns
          ,SCHEMA_NAME(RT.schema_id) + '.' + RT.[name] AS ReferencedTable
          ,STUFF(ReferencedColumns.ReferencedColumns, 1, 2, '') AS ReferencedColumns
        FROM
          sys.foreign_keys FK
          INNER JOIN sys.tables FT
          ON FT.object_id = FK.parent_object_id
          INNER JOIN sys.tables RT
          ON RT.object_id = FK.referenced_object_id
          CROSS APPLY
          (
            SELECT
              ', ' + iFC.[name] AS [text()]
            FROM
              sys.foreign_key_columns iFKC
              INNER JOIN sys.columns iFC
              ON iFC.object_id = iFKC.parent_object_id
                AND iFC.column_id = iFKC.parent_column_id
            WHERE
              iFKC.constraint_object_id = FK.object_id
            ORDER BY
              iFC.[name]
            FOR XML PATH('')
          ) ForeignColumns (ForeignColumns)
          CROSS APPLY
          (
            SELECT
              ', ' + iRC.[name]AS [text()]
            FROM
              sys.foreign_key_columns iFKC
              INNER JOIN sys.columns iRC
              ON iRC.object_id = iFKC.referenced_object_id
                AND iRC.column_id = iFKC.referenced_column_id
            WHERE
              iFKC.constraint_object_id = FK.object_id
            ORDER BY
              iRC.[name]
            FOR XML PATH('')
          ) ReferencedColumns (ReferencedColumns)
        

        【讨论】:

          【解决方案7】:
          select * from information_schema.REFERENTIAL_CONSTRAINTS where 
          UNIQUE_CONSTRAINT_SCHEMA = 'SCHEMA_NAME' 
          

          这将列出带有SCHEMA_NAMEenter image description here的约束

          【讨论】:

          • 这显示了无效的列名来代替 Table_name。请建议,这对我有帮助。
          【解决方案8】:

          如果您有LINQPad(它是免费的),我刚刚编写的这个脚本将列出您数据库中每个表之间的所有可能路径。

          给定以下数据库:

          ...脚本将产生以下输出:

          或者你可以在脚本顶部设置longestOnly标志,它只会输出最长的路径:

          这是脚本:

          var longestOnly = true;
          
          var pathLists = new List<List<string>>();
          
          foreach (var table in Mapping.GetTables()) {
              var subPaths = new List<string>();
              pathLists.Add(subPaths);
              subPaths.Add(table.TableName);
          
              Go(table, subPaths);
          }
          
          var pathStrings = pathLists
              .Select(p => string.Join(", ", p))
              .Distinct()
              .OrderBy(p => p)
              .ToList();
              
          if (longestOnly) {
              pathStrings.RemoveAll(z => pathStrings.Any(i => i != z && i.Contains(z)));
          } else {
              pathStrings.RemoveAll(z => pathStrings.Any(i => i != z && i.StartsWith(z)));
          }
          
          pathStrings.Dump();
          
          
          void Go(System.Data.Linq.Mapping.MetaTable table, List<string> paths)
          {
              foreach (var association in table.RowType.Associations) {
                  var subPaths = paths.Concat(new List<string>()).ToList(); // create a copy
                  pathLists.Add(subPaths);
                  var subPathTableName = association.OtherType.Table.TableName;
          
                  if (!subPaths.Contains(subPathTableName)) {
                      subPaths.Add(subPathTableName);
                      var subPathTable = Mapping.GetTable(association.OtherMember.DeclaringType.Type);
                      if (subPathTable != null) {
                          Go(subPathTable, subPaths);
                      }
                  }
              }
          }
          
          

          对于复杂的数据库,这可能需要非常长的时间才能完成,并且会返回大量的结果列表。我需要为工作而写这个,最终的结果让我感到非常失败。 :)

          我找不到其他可以做到这一点的东西,所以我很满意。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-01-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多