﻿<?xml version='1.0' encoding='UTF-8'?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>SQLServerCentral / Discuss Content Posted by Jeffrey Yao / Article Discussions / Article Discussions by Author  / Making Good Use of Sysforeignkeys Table - Part 1: Display table relati / Latest Posts</title><generator>InstantForum.NET v2.9.0</generator><description>SQLServerCentral</description><link>http://www.sqlservercentral.com/Forums/</link><webMaster>notifications@sqlservercentral.com</webMaster><lastBuildDate>Tue, 21 May 2013 18:11:32 GMT</lastBuildDate><ttl>20</ttl><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;Right! I thought I'd look at adapting this script yet again to use the new system views in SQL2005, when I started to think that this is a really great idea but it needs to be pulled into the 21st century slightly. What I mean is that if you were serious about using this to document table dependancies, then you'd probably like a little more information and maybe in a slightly pretier format. What I've come up with is a FOR XML EXPLICIT query to retrieve the database metadata as XML and an XSL transformation to represent the table relationships. I think this is the way forward as you could extend the info in the XML as well as reuse existing information to generate other types of reports depending on what it is you want to document.&lt;/P&gt;&lt;P&gt;Therefore, for your reading pleasure please find below the SQL script to create the XML followed by the XSLT file.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;PLEASE NOTE: I have spent a minimum of time on this and there may well be some bugs in the final report (I'm by ne means and XSL expert) so please use this at your own risk!!&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;In saying that, any comments on bugs/improvements that people see would be very happily recieved.&lt;/P&gt;&lt;P&gt;SQL QUERY&lt;/P&gt;&lt;P&gt;Declare @tmpXML Table ( tag int, parent int, [root!1!!element] int, [root!1!databasename] Varchar(255), [root!1!databaseid] int, [tables!2!!element] int, [table!3!!element] Varchar(255), [table!3!id] int, [column!4!!element] Varchar(255), [column!4!id] int, [relationships!5!!element] int, [tablerelationship!6!!element] Varchar(255), [tablerelationship!6!referencedkeytableid] int, [tablerelationship!6!foreignkeytableid] int, [relationship!7!!element] Varchar(255), [relationship!7!id] int, [columnrelationship!8!referencedkeycolumn] Varchar(255), [columnrelationship!8!foreignkeycolumn] Varchar(255), sortorder Varchar(200))&lt;/P&gt;&lt;P&gt;Insert @tmpXML(tag,parent,[root!1!!element],[root!1!databasename],[root!1!databaseid],sortorder)Select 1,0,Null,db_name(), db_id(),0&lt;/P&gt;&lt;P&gt;Insert @tmpXML(tag,parent,[tables!2!!element],sortorder)Select 2,1,Null,0&lt;/P&gt;&lt;P&gt;Insert @tmpXML(tag,parent,[relationships!5!!element],sortorder)Select 5,1,Null,1&lt;/P&gt;&lt;P&gt;Insert @tmpXML ( tag, parent, [table!3!!element], [table!3!id], sortorder)Select 3, 2, name, id, Substring('00000000000', 1, 11 - Len(Cast(id As Varchar))) + Cast(id As Varchar)From sys.sysobjects oWhere OBJECTPROPERTY(o.id, N'IsUserTable') = 1Order By o.name&lt;/P&gt;&lt;P&gt;Insert @tmpXML ( tag, parent, [column!4!!element], [column!4!id], sortorder)Select 4, 3, c.name, c.colid, Substring('00000000000', 1, 11 - Len(Cast(o.id As Varchar))) + Cast(o.id As Varchar) + Substring('0000', 1, 4 - Len(Cast(c.colid As Varchar))) + Cast(c.colid As Varchar)From sys.sysobjects oJoin sys.syscolumns c  On o.ID = c.IDWhere OBJECTPROPERTY(o.id, N'IsUserTable') = 1Order By o.name, c.name&lt;/P&gt;&lt;P&gt;Insert @tmpXML ( tag, parent, [tablerelationship!6!!element], [tablerelationship!6!referencedkeytableid], [tablerelationship!6!foreignkeytableid], sortorder)Select Distinct 6, 5, '', parent_object_id, referenced_object_id, Substring('10000000000', 1, 11 - Len(Cast(fk.referenced_object_id As Varchar))) + Cast(fk.referenced_object_id As Varchar) + Substring('10000000000', 1, 11 - Len(Cast(fk.parent_object_id As Varchar))) + Cast(fk.parent_object_id As Varchar)From sys.foreign_keys fk&lt;/P&gt;&lt;P&gt;Insert @tmpXML ( tag, parent, [relationship!7!!element], [relationship!7!id], sortorder)Select Distinct 7, 6, fk.[name], fk.[object_id], Substring('10000000000', 1, 11 - Len(Cast(fk.referenced_object_id As Varchar))) + Cast(fk.referenced_object_id As Varchar) + Substring('10000000000', 1, 11 - Len(Cast(fk.parent_object_id As Varchar))) + Cast(fk.parent_object_id As Varchar) + Substring('00000000000', 1, 11 - Len(Cast(fk.[object_id] As Varchar))) + Cast(fk.[object_id] As Varchar)From sys.foreign_keys fk&lt;/P&gt;&lt;P&gt;Insert @tmpXML ( tag, parent, [columnrelationship!8!referencedkeycolumn], [columnrelationship!8!foreignkeycolumn], sortorder)Select 8, 7, rc.name, fc.name, Substring('10000000000', 1, 11 - Len(Cast(fkc.referenced_object_id As Varchar))) + Cast(fkc.referenced_object_id As Varchar) + Substring('10000000000', 1, 11 - Len(Cast(fkc.parent_object_id As Varchar))) + Cast(fkc.parent_object_id As Varchar) + Substring('00000000000', 1, 11 - Len(Cast(fkc.constraint_object_id As Varchar))) + Cast(fkc.constraint_object_id As Varchar) + rc.nameFrom sys.foreign_key_columns fkcJoin sys.columns fc  On fkc.parent_object_id = fc.[object_id]  And fkc.parent_column_id = fc.column_idJoin sys.columns rc  On fkc.referenced_object_id = rc.[object_id]  And fkc.referenced_column_id = rc.column_id&lt;/P&gt;&lt;P&gt;Select tag, parent, [root!1!!element], [root!1!databasename], [root!1!databaseid], [tables!2!!element], [table!3!!element], [table!3!id], [column!4!!element], [column!4!id], [relationships!5!!element], [tablerelationship!6!!element], [tablerelationship!6!referencedkeytableid], [tablerelationship!6!foreignkeytableid], [relationship!7!!element], [relationship!7!id], [columnrelationship!8!referencedkeycolumn], [columnrelationship!8!foreignkeycolumn]From @tmpXMLOrder By sortorderFor XML Explicit&lt;/P&gt;&lt;DIV&gt;&lt;SPAN style="WIDTH: 100px" onclick=this.focus();&gt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;P&gt; &lt;/P&gt;&lt;DIV&gt;XSL TRANSFORMATION&lt;/DIV&gt;&lt;DIV&gt; &amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&amp;lt;xsl:stylesheet version="2.0" xmlns:xsl="&lt;A href="http://www.w3.org/1999/XSL/Transform"&gt;http://www.w3.org/1999/XSL/Transform&lt;/A&gt;"&amp;gt;&lt;/DIV&gt;&lt;DIV&gt; &amp;lt;xsl:output method="html"/&amp;gt; &amp;lt;xsl:preserve-space elements="text"/&amp;gt;  &amp;lt;xsl:template match="column"&amp;gt;   &amp;lt;td bgcolor="#fffacd"&amp;gt;    &amp;lt;xsl:value-of select="text()"/&amp;gt;   &amp;lt;/td&amp;gt; &amp;lt;/xsl:template&amp;gt;  &amp;lt;xsl:template match="table"&amp;gt;  &amp;lt;xsl:param name="cnt"/&amp;gt;  &amp;lt;xsl:param name="root" select="'0'"/&amp;gt;  &amp;lt;xsl:param name="allowselfref" select="'1'"/&amp;gt;  &amp;lt;xsl:param name="relationshipid" select="''"/&amp;gt;  &amp;lt;xsl:param name="referencedkeytableid" select="''"/&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;  &amp;lt;xsl:variable name="id" select="@id"/&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;  &amp;lt;xsl:if test="count(//relationships/tablerelationship[@foreignkeytableid=$id])=0 or $root!=1"&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;   &amp;lt;xsl:variable name="tableformat"&amp;gt;    margin-left: 5px; height: 21px; font-size: 10px; font-family: Arial; position: relative; left: &amp;lt;xsl:value-of select="$cnt"/&amp;gt;px; border-left: #000000 1px solid;   &amp;lt;/xsl:variable&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;   &amp;lt;table&amp;gt;    &amp;lt;xsl:attribute name="style"&amp;gt;     &amp;lt;xsl:value-of select="$tableformat"/&amp;gt;    &amp;lt;/xsl:attribute&amp;gt;    &amp;lt;tr height="15px"&amp;gt;     &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;    &amp;lt;/tr&amp;gt;    &amp;lt;tr&amp;gt;     &amp;lt;td&amp;gt;      &amp;lt;xsl:for-each select="//relationships/tablerelationship[@referencedkeytableid=$referencedkeytableid][@foreignkeytableid=$id]/relationship"&amp;gt;       &amp;lt;xsl:value-of select="text()"/&amp;gt;       &amp;lt;span style="font-size: 8px;"&amp;gt;        &amp;lt;xsl:value-of select="' (ID:'"/&amp;gt;        &amp;lt;xsl:value-of select="@id"/&amp;gt;        &amp;lt;xsl:value-of select="')'"/&amp;gt;       &amp;lt;/span&amp;gt;       &amp;lt;xsl:for-each select="columnrelationship"&amp;gt;        &amp;lt;xsl:value-of select="' : '"/&amp;gt;        &amp;lt;xsl:value-of select="@referencedkeycolumn"/&amp;gt; to &amp;lt;xsl:value-of select="@foreignkeycolumn"/&amp;gt;       &amp;lt;/xsl:for-each&amp;gt;       &amp;lt;br/&amp;gt;      &amp;lt;/xsl:for-each&amp;gt;     &amp;lt;/td&amp;gt;    &amp;lt;/tr&amp;gt;   &amp;lt;/table&amp;gt;   &amp;lt;table&amp;gt;    &amp;lt;xsl:attribute name="style"&amp;gt;     &amp;lt;xsl:value-of select="$tableformat"/&amp;gt;    &amp;lt;/xsl:attribute&amp;gt;    &amp;lt;tr&amp;gt;     &amp;lt;td&amp;gt;      &amp;lt;b&amp;gt;       &amp;lt;xsl:value-of select="text()"/&amp;gt;      &amp;lt;/b&amp;gt;      &amp;lt;xsl:if test="$allowselfref=0"&amp;gt;       &amp;lt;i&amp;gt;        &amp;lt;xsl:value-of select="' (Self Referential)'"/&amp;gt;       &amp;lt;/i&amp;gt;      &amp;lt;/xsl:if&amp;gt;     &amp;lt;/td&amp;gt;    &amp;lt;/tr&amp;gt;   &amp;lt;/table&amp;gt;   &amp;lt;table&amp;gt;    &amp;lt;xsl:attribute name="style"&amp;gt;     &amp;lt;xsl:value-of select="$tableformat"/&amp;gt;  border-bottom: #000000 1px solid;    &amp;lt;/xsl:attribute&amp;gt;    &amp;lt;tr&amp;gt;     &amp;lt;xsl:apply-templates select="column"/&amp;gt;    &amp;lt;/tr&amp;gt;   &amp;lt;/table&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;   &amp;lt;xsl:for-each select="//relationships/tablerelationship[@referencedkeytableid=$id]"&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;    &amp;lt;xsl:variable name="foreignkeytableid" select="@foreignkeytableid"/&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;    &amp;lt;xsl:if test="$id!=$foreignkeytableid and $allowselfref=1"&amp;gt;     &amp;lt;xsl:apply-templates select="//tables/table[@id=$foreignkeytableid]"&amp;gt;      &amp;lt;xsl:with-param name="cnt" select="$cnt+50"/&amp;gt;      &amp;lt;xsl:with-param name="allowselfref" select="1"/&amp;gt;      &amp;lt;xsl:with-param name="relationshipid" select="@id"/&amp;gt;      &amp;lt;xsl:with-param name="referencedkeytableid" select="@referencedkeytableid"/&amp;gt;     &amp;lt;/xsl:apply-templates&amp;gt;    &amp;lt;/xsl:if&amp;gt;    &amp;lt;xsl:if test="$id=$foreignkeytableid and $allowselfref=1"&amp;gt;     &amp;lt;xsl:apply-templates select="//tables/table[@id=$foreignkeytableid]"&amp;gt;      &amp;lt;xsl:with-param name="cnt" select="$cnt+50"/&amp;gt;      &amp;lt;xsl:with-param name="allowselfref" select="0"/&amp;gt;      &amp;lt;xsl:with-param name="relationshipid" select="@id"/&amp;gt;      &amp;lt;xsl:with-param name="referencedkeytableid" select="@referencedkeytableid"/&amp;gt;     &amp;lt;/xsl:apply-templates&amp;gt;    &amp;lt;/xsl:if&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;   &amp;lt;/xsl:for-each&amp;gt;  &amp;lt;/xsl:if&amp;gt; &amp;lt;/xsl:template&amp;gt;  &amp;lt;xsl:template match="tables"&amp;gt;  &amp;lt;xsl:apply-templates select="table"&amp;gt;   &amp;lt;xsl:with-param name="cnt" select="0"/&amp;gt;   &amp;lt;xsl:with-param name="root" select="1"/&amp;gt;  &amp;lt;/xsl:apply-templates&amp;gt; &amp;lt;/xsl:template&amp;gt;  &amp;lt;xsl:template match="root"&amp;gt;  &amp;lt;html&amp;gt;   &amp;lt;body&amp;gt;    &amp;lt;pre&amp;gt;     &amp;lt;xsl:apply-templates select="tables"/&amp;gt;    &amp;lt;/pre&amp;gt;   &amp;lt;/body&amp;gt;  &amp;lt;/html&amp;gt; &amp;lt;/xsl:template&amp;gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;/DIV&gt;&lt;FONT color=#0000ff size=2&gt;&lt;P&gt;&lt;FONT color=#111111&gt;At the moment the XSL creates a new tree for every table in the database that doesn't exist as a foreign key in another relationship. You could easily change the filter on the call to the table template to report on a specific table if you liked. Also this only reports from the parent down but once again with a few edits you could extend the XSL to work in the other direction.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT color=#111111 size=2&gt;&lt;FONT color=#111111&gt;Happy&lt;/FONT&gt; documenting &lt;img src='images/emotions/cool.gif' height='20' width='20' border='0' title='Cool' align='absmiddle'&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT color=#111111&gt;Rob&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;</description><pubDate>Wed, 03 May 2006 05:08:00 GMT</pubDate><dc:creator>robertm</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;In case anyone is interested, Listed below is a bottom-up version of the proc:&lt;/P&gt;&lt;P&gt;CREATE PROCEDURE dbo.DisplayBottomUpTableHierarchy( @TableName VARCHAR(128), @SpaceLen INT = -4 OUTPUT)ASBEGIN&lt;/P&gt;&lt;P&gt; DECLARE @Child VARCHAR(100) SET @SpaceLen = @SpaceLen + 4  IF @TableName IS NOT NULL BEGIN  IF EXISTS(SELECT * FROM sysforeignkeys WHERE fkeyid = OBJECT_ID(@TableName))  BEGIN         IF @SpaceLen &amp;lt;= 0          PRINT @TableName   ELSE     PRINT SPACE(@SpaceLen) + '|---' + @TableName         IF EXISTS(SELECT * FROM sysforeignkeys WHERE fkeyid = OBJECT_ID(@TableName) AND fkeyid = rkeyid)             PRINT SPACE(@SpaceLen) + '|---' + @TableName         DECLARE curChild CURSOR LOCAL FOR    SELECT OBJECT_NAME(rkeyid) AS child FROM sysforeignkeys    WHERE fkeyid = OBJECT_ID(@TableName) AND fkeyid &amp;lt;&amp;gt; rkeyid          OPEN curChild   FETCH NEXT FROM curChild INTO @Child   WHILE @@fetch_status = 0   BEGIN    EXEC DisplayBottomUpTableHierarchy      @TableName = @Child,      @SpaceLen = @SpaceLen OUTPUT    FETCH NEXT FROM curChild into @Child   END   CLOSE curChild   DEALLOCATE curChild  END  ELSE  BEGIN         IF @SpaceLen &amp;lt;= 0          PRINT @TableName   ELSE     PRINT SPACE(@SpaceLen) + '|---' + @TableName  END END SET @SpaceLen = @SpaceLen - 4 RETURNEND&lt;/P&gt;&lt;P&gt; &lt;/P&gt;</description><pubDate>Mon, 24 Apr 2006 13:21:00 GMT</pubDate><dc:creator>Roland Schaer</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;Thanks, Kenneth for your great work to help improve my code. Really appreciate it !&lt;/P&gt;&lt;P&gt;Jeffrey&lt;/P&gt;</description><pubDate>Thu, 05 Jan 2006 10:58:00 GMT</pubDate><dc:creator>jeffrey yao</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;Thank you so much for such a wonderfull piece of code. I was working on a project and what you have in your code is exactly what I was looking for...&lt;/P&gt;&lt;P&gt;Its really a very good piece of code to keep you document upto date with minmum efforts.&lt;/P&gt;&lt;P&gt;&lt;img src='images/emotions/smile.gif' height='20' width='20' border='0' title='Smile' align='absmiddle'&gt;&lt;/P&gt;</description><pubDate>Fri, 21 Oct 2005 07:42:00 GMT</pubDate><dc:creator>Salvador Anthony Desa</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;if NOT exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_DisplayTableRelation]') and OBJECTPROPERTY(id, N'IsProcedure') = 1) exec sp_executesql N'CREATE procedure usp_DisplayTableRelation AS print 1'if NOT exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_DisplayTableRelation1]') and OBJECTPROPERTY(id, N'IsProcedure') = 1) exec sp_executesql N'CREATE procedure usp_DisplayTableRelation1 AS print 1'go&lt;/P&gt;&lt;P&gt;alter procedure usp_DisplayTableRelation  @table_name nvarchar(128) -- the procedure will try to find all the child tables for the table @table_nameasbegin -- sp    if @table_name is null        return if not exists (select * from tempdb.dbo.sysobjects where name = N'##UsedTableName' )  create table ##UsedTableName (TableName nvarchar(128))-- use to track recursive calls to same table else delete from ##UsedTableName if not exists (select * from tempdb.dbo.sysobjects where name = N'##DisplayTableRelation' )  create table ##DisplayTableRelation (Relation nvarchar(4000))-- use to track recursive calls to same table else delete from ##DisplayTableRelation&lt;/P&gt;&lt;P&gt;    exec usp_DisplayTableRelation1 @table_name = @table_name&lt;/P&gt;&lt;P&gt;    select * from ##DisplayTableRelation        drop table ##UsedTableName    drop table ##DisplayTableRelation    returnend --spgo&lt;/P&gt;&lt;P&gt;alter procedure usp_DisplayTableRelation1  @table_name nvarchar(128) -- the procedure will try to find all the child tables for the table @table_name, @space_len int = -4 output -- for insert into ##DisplayTableRelation (Relation) selecting position purposeasbegin -- sp    declare @child nvarchar(128)    declare @usedTable nvarchar(100)    if @table_name is null        return if not exists (select * from tempdb.dbo.sysobjects where name = N'##DisplayTableRelation' ) begin  exec usp_DisplayTableRelation @table_name  return end    set @space_len = @space_len + 4&lt;/P&gt;&lt;P&gt;    if not exists (select * from sysforeignkeys where rkeyid = object_id(@table_name) )    begin -- leaf level        if @space_len &amp;lt;= 0            insert into ##DisplayTableRelation (Relation) select @table_name        else             insert into ##DisplayTableRelation (Relation) select space(@space_len) + '|---' + @table_name&lt;/P&gt;&lt;P&gt;        set @space_len = @space_len - 4        return    end -- leaf level    else -- the @table_name table exists    begin -- else  set @usedTable = N''  if exists (select * from ##UsedTableName where TableName = @table_name)   set @usedTable = N' (Loop Reference)'  else insert into ##UsedTableName (TableName) select @table_name        if @space_len &amp;lt;= 0            insert into ##DisplayTableRelation (Relation) select @table_name + @usedTable        else             insert into ##DisplayTableRelation (Relation) select space(@space_len) + '|---' + @table_name + @usedTable&lt;/P&gt;&lt;P&gt;        if (@usedTable = N'' --first time   and exists ( select * from sysforeignkeys where rkeyid = object_id(@table_name) and rkeyid = fkeyid)) -- self referenced    insert into ##DisplayTableRelation (Relation) select space(@space_len+4) + '|---' + @table_name&lt;/P&gt;&lt;P&gt;        declare curChild cursor local for        select object_name(fkeyid) as child from sysforeignkeys        where rkeyid = object_id(@table_name) and rkeyid &amp;lt;&amp;gt; fkeyid &lt;/P&gt;&lt;P&gt;        open curChild        fetch next from curChild into @child                while @@fetch_status = 0         begin -- cursor loop             if (@usedTable = N'') exec usp_DisplayTableRelation1 @table_name = @child, @space_len = @space_len output              fetch next from curChild into @child          end -- cursor loop&lt;/P&gt;&lt;P&gt;           close curChild           deallocate curChild    end --else    set @space_len = @space_len - 4    returnend --sp-- copied to notepad, then copied it to this post&lt;/P&gt;</description><pubDate>Wed, 01 Jun 2005 15:01:00 GMT</pubDate><dc:creator>Kenneth Lee</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>Sorry about the double spacing.  That's this posting routine getting involved.</description><pubDate>Wed, 01 Jun 2005 14:59:00 GMT</pubDate><dc:creator>Kenneth Lee</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;FONT size=2&gt;&lt;P&gt;if NOT exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_DisplayTableRelation]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)&lt;/P&gt;&lt;P&gt;exec sp_executesql N'CREATE procedure usp_DisplayTableRelation AS print 1'&lt;/P&gt;&lt;P&gt;if NOT exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_DisplayTableRelation1]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)&lt;/P&gt;&lt;P&gt;exec sp_executesql N'CREATE procedure usp_DisplayTableRelation1 AS print 1'&lt;/P&gt;&lt;P&gt;go&lt;/P&gt;&lt;P&gt;alter procedure usp_DisplayTableRelation&lt;/P&gt;&lt;P&gt;@table_name nvarchar(128) -- the procedure will try to find all the child tables for the table @table_name&lt;/P&gt;&lt;P&gt;as&lt;/P&gt;&lt;P&gt;begin -- sp&lt;/P&gt;&lt;P&gt;if @table_name is null&lt;/P&gt;&lt;P&gt;return&lt;/P&gt;&lt;P&gt;if not exists (select * from tempdb.dbo.sysobjects where name = N'##UsedTableName' )&lt;/P&gt;&lt;P&gt;create table ##UsedTableName (TableName nvarchar(128))-- use to track recursive calls to same table&lt;/P&gt;&lt;P&gt;else delete from ##UsedTableName&lt;/P&gt;&lt;P&gt;if not exists (select * from tempdb.dbo.sysobjects where name = N'##DisplayTableRelation' )&lt;/P&gt;&lt;P&gt;create table ##DisplayTableRelation (Relation nvarchar(4000))-- use to track recursive calls to same table&lt;/P&gt;&lt;P&gt;else delete from ##DisplayTableRelation&lt;/P&gt;&lt;P&gt;exec usp_DisplayTableRelation1 @table_name = @table_name&lt;/P&gt;&lt;P&gt;select * from ##DisplayTableRelation&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;drop table ##UsedTableName&lt;/P&gt;&lt;P&gt;drop table ##DisplayTableRelation&lt;/P&gt;&lt;P&gt;return&lt;/P&gt;&lt;P&gt;end --sp&lt;/P&gt;&lt;P&gt;go&lt;/P&gt;&lt;P&gt;alter procedure usp_DisplayTableRelation1&lt;/P&gt;&lt;P&gt;@table_name nvarchar(128) -- the procedure will try to find all the child tables for the table @table_name&lt;/P&gt;&lt;P&gt;, @space_len int = -4 output -- for insert into ##DisplayTableRelation (Relation) selecting position purpose&lt;/P&gt;&lt;P&gt;as&lt;/P&gt;&lt;P&gt;begin -- sp&lt;/P&gt;&lt;P&gt;declare @child nvarchar(128)&lt;/P&gt;&lt;P&gt;declare @usedTable nvarchar(100)&lt;/P&gt;&lt;P&gt;if @table_name is null&lt;/P&gt;&lt;P&gt;return&lt;/P&gt;&lt;P&gt;if not exists (select * from tempdb.dbo.sysobjects where name = N'##DisplayTableRelation' )&lt;/P&gt;&lt;P&gt;begin&lt;/P&gt;&lt;P&gt;exec usp_DisplayTableRelation @table_name&lt;/P&gt;&lt;P&gt;return&lt;/P&gt;&lt;P&gt;end&lt;/P&gt;&lt;P&gt;set @space_len = @space_len + 4&lt;/P&gt;&lt;P&gt;if not exists (select * from sysforeignkeys where rkeyid = object_id(@table_name) )&lt;/P&gt;&lt;P&gt;begin -- leaf level&lt;/P&gt;&lt;P&gt;if @space_len &amp;lt;= 0&lt;/P&gt;&lt;P&gt;insert into ##DisplayTableRelation (Relation) select @table_name&lt;/P&gt;&lt;P&gt;else &lt;/P&gt;&lt;P&gt;insert into ##DisplayTableRelation (Relation) select space(@space_len) + '|---' + @table_name&lt;/P&gt;&lt;P&gt;set @space_len = @space_len - 4&lt;/P&gt;&lt;P&gt;return&lt;/P&gt;&lt;P&gt;end -- leaf level&lt;/P&gt;&lt;P&gt;else -- the @table_name table exists&lt;/P&gt;&lt;P&gt;begin -- else&lt;/P&gt;&lt;P&gt;set @usedTable = N''&lt;/P&gt;&lt;P&gt;if exists (select * from ##UsedTableName where TableName = @table_name)&lt;/P&gt;&lt;P&gt;set @usedTable = N' (Loop Reference)'&lt;/P&gt;&lt;P&gt;else insert into ##UsedTableName (TableName) select @table_name&lt;/P&gt;&lt;P&gt;if @space_len &amp;lt;= 0&lt;/P&gt;&lt;P&gt;insert into ##DisplayTableRelation (Relation) select @table_name + @usedTable&lt;/P&gt;&lt;P&gt;else &lt;/P&gt;&lt;P&gt;insert into ##DisplayTableRelation (Relation) select space(@space_len) + '|---' + @table_name + @usedTable&lt;/P&gt;&lt;P&gt;if (@usedTable = N'' --first time&lt;/P&gt;&lt;P&gt;and exists ( select * from sysforeignkeys where rkeyid = object_id(@table_name) and rkeyid = fkeyid)) -- self referenced&lt;/P&gt;&lt;P&gt;insert into ##DisplayTableRelation (Relation) select space(@space_len+4) + '|---' + @table_name&lt;/P&gt;&lt;P&gt;declare curChild cursor local for&lt;/P&gt;&lt;P&gt;select object_name(fkeyid) as child from sysforeignkeys&lt;/P&gt;&lt;P&gt;where rkeyid = object_id(@table_name) and rkeyid &amp;lt;&amp;gt; fkeyid &lt;/P&gt;&lt;P&gt;open curChild&lt;/P&gt;&lt;P&gt;fetch next from curChild into @child&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;while @@fetch_status = 0&lt;/P&gt;&lt;P&gt;begin -- cursor loop&lt;/P&gt;&lt;P&gt;if (@usedTable = N'') exec usp_DisplayTableRelation1 @table_name = @child, @space_len = @space_len output &lt;/P&gt;&lt;P&gt;fetch next from curChild into @child&lt;/P&gt;&lt;P&gt;end -- cursor loop&lt;/P&gt;&lt;P&gt;close curChild&lt;/P&gt;&lt;P&gt;deallocate curChild&lt;/P&gt;&lt;P&gt;end --else&lt;/P&gt;&lt;P&gt;set @space_len = @space_len - 4&lt;/P&gt;&lt;P&gt;return&lt;/P&gt;&lt;P&gt;end --sp&lt;/P&gt;&lt;/FONT&gt;</description><pubDate>Wed, 01 Jun 2005 14:58:00 GMT</pubDate><dc:creator>Kenneth Lee</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description> I immediately blew up on a recursive loop count error, basically because your code can put the table references in an infinite loop.  Here's an extract of the output after I modified your code.   |---Contact        |---Contact        |---MortgageInsurance            |---ContactOffice                |---LoanFeeTemplate                    |---Contact (Loop Reference)First I put in a temp table to track what tables have already had tree output.  Oh, yuck, now there's all these add row messages in the middle of your print.  OK add a second table to hold the output.  Hmmm, now there's maintenance of these temp tables and no way for your recursive loop to know when the table is done.  Make two procs, one to handle the tables and one to recursively loop through the list.  Hmmm, your self-refference is on the same level, may as well fix that as well.  I'll put my finished code (that also takes care of the error message your newbie had.) in a new post.</description><pubDate>Wed, 01 Jun 2005 14:57:00 GMT</pubDate><dc:creator>Kenneth Lee</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;Thanks, Robertm, for pointing out the bug. Really appreciate it !&lt;/P&gt;&lt;P&gt;Sameer, I have replied your email. Pls check it. &lt;/P&gt;&lt;P&gt;This SP will only display the relationship tree from the top to bottom. So if your table is at on the leaf level of a tree, the SP will only display the table itself. &lt;img src='images/emotions/smile.gif' height='20' width='20' border='0' title='Smile' align='absmiddle'&gt;&lt;/P&gt;&lt;P&gt;In future, I may revise this SP by adding a "switch" control to allow display a "reverse" relationship tree, i.e. from the bottom to top.  &lt;/P&gt;&lt;P&gt;I am honored if my script can be of any help to SCC community.&lt;/P&gt;</description><pubDate>Wed, 01 Jun 2005 14:06:00 GMT</pubDate><dc:creator>jeffrey yao</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;This looks to be very good SP.&lt;/P&gt;&lt;P&gt;I have small problem creating this sp , get following message&lt;/P&gt;&lt;P&gt;Cannot add rows to sysdepends for the current stored procedure because it depends on the missing object 'usp_DisplayTableRelation'. The stored procedure will still be created.&lt;/P&gt;&lt;P&gt;Still, I continued but not resulting anything else then tblname that is input.&lt;/P&gt;&lt;P&gt;Will appriciate your help to resolve the problem..&lt;/P&gt;&lt;P&gt; &lt;/P&gt;&lt;P&gt;Thanks,&lt;/P&gt;&lt;P&gt;Sameer&lt;/P&gt;&lt;P&gt; &lt;/P&gt;&lt;P&gt; &lt;/P&gt;&lt;P&gt; &lt;/P&gt;</description><pubDate>Wed, 01 Jun 2005 07:23:00 GMT</pubDate><dc:creator>Sameer Raval</dc:creator></item><item><title>RE: Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>&lt;P&gt;This is a really great use of data in the sys tables of your database, especially when it comes to providing documentation.&lt;/P&gt;&lt;P&gt;One small bug in the procedure however is that it will duplicate parent child relationships in the resultant tree between two tables where the relationship is composed of a composite key. To rectify this you need to simply pouplate the cursor curChild with a distinct list of foreign keys, e.g.&lt;/P&gt;&lt;P&gt;declare curChild cursor local for        select &lt;B&gt;distinct&lt;/B&gt; object_name(fkeyid) as child from sysforeignkeys        where rkeyid = object_id(@table_name) and rkeyid &amp;lt;&amp;gt; fkeyid &lt;/P&gt;</description><pubDate>Wed, 01 Jun 2005 03:27:00 GMT</pubDate><dc:creator>robertm</dc:creator></item><item><title>Making Good Use of Sysforeignkeys Table - Part 1: Display table relati</title><link>http://www.sqlservercentral.com/Forums/Topic117824-164-1.aspx</link><description>Comments posted to this topic are about the content posted at &lt;A HREF=http://www.sqlservercentral.com/columnists/jyao/makinggooduseofsysforeignkeystablepart1displaytabl.asp&gt;http://www.sqlservercentral</description><pubDate>Wed, 26 May 2004 09:53:00 GMT</pubDate><dc:creator>jeffrey yao</dc:creator></item></channel></rss>