關於網友的獲取MSSQL外來鍵資訊的問題的探討

sqysl發表於2009-06-09

昨晚,網友又提出了一個問題: 
求一個SQL查詢語句,根據給定的表名和欄位名返回(外來鍵約束名,引用的主鍵名稱,引用的表名,引用的欄位名),謝謝
結果,我發出了在MSSQL2005上的跟蹤語句:
select Fk.name, Fk.object_id, Fk.is_disabled, Fk.is_not_for_replication, Fk.delete_referential_action, Fk.update_referential_action,
object_name(Fk.parent_object_id) as Fk_table_name, schema_name(Fk.schema_id) as Fk_table_schema, TbR.name as Pk_table_name, schema_name(TbR.schema_id)
Pk_table_schema, col_name(Fk.parent_object_id, Fk_Cl.parent_column_id) as Fk_col_name, col_name(Fk.referenced_object_id, Fk_Cl.referenced_column_id) as Pk_col_name,
Fk_Cl.constraint_column_id, Fk.is_not_trusted from sys.foreign_keys Fk left outer join sys.tables TbR on TbR.object_id = Fk.referenced_object_id inner join
sys.foreign_key_columns Fk_Cl on Fk_Cl.constraint_object_id = Fk.object_id where Fk.parent_object_id = object_id(N'dbo.Table_1') or Fk.referenced_object_id =
object_id(N'dbo.Table_1') order by Fk.object_id, Fk_Cl.constraint_column_id
結果,她試驗了一下不行,因為她的系統是MSSQL2K,因此,我就又對MSSQL2K進行了跟蹤,結果發現,MSSQL2K裡,很多系統資訊不是透過SQL語句獲取的,而是透過sp_過程獲取的,於是,就開始研究如何獲取sp_過程返回的結果,最後試驗成功,這也算是解決mssql2k類似問題的一個思路吧,mssql2k裡的系統檢視和表沒有mssql2005裡那麼豐富,所以只能透過sp_獲取了,下面是我整理的結果:
create table test_ref(
pk_tab varchar(20),fk_tab varchar(20),constraints varchar(20),status varchar(20),
ckeycol1 varchar(20),ckeycol2 varchar(20),ckeycol3 varchar(20),ckeycol4 varchar(20),
ckeycol5 varchar(20),ckeycol6 varchar(20),ckeycol7 varchar(20),ckeycol8 varchar(20),
ckeycol9 varchar(20),ckeycol10 varchar(20),ckeycol11 varchar(20),ckeycol12 varchar(20),
ckeycol13 varchar(20),ckeycol14 varchar(20),ckeycol15 varchar(20),ckeycol16 varchar(20),
crefcol1 varchar(20),crefcol2 varchar(20),crefcol3 varchar(20),crefcol4 varchar(20),
crefcol5 varchar(20),crefcol6 varchar(20),crefcol7 varchar(20),crefcol8 varchar(20),
crefcol9 varchar(20),crefcol10 varchar(20),crefcol11 varchar(20),crefcol12 varchar(20),
crefcol13 varchar(20),crefcol14 varchar(20),crefcol15 varchar(20),crefcol16 varchar(20),
pk_table_owner varchar(20),fk_table_owner varchar(20),deletecascade varchar(20),
updatecascade varchar(20))
insert into test_ref exec sp_MStablerefs N'dbo.t1', N'actualtables', N'both', null
select pk_tab as 主鍵表,fk_tab as 外來鍵表,constraints as 約束名,ckeycol1 as 主鍵列1,ckeycol2 as 主鍵列2,ckeycol3 as 主鍵列3 ,
crefcol1 as 外來鍵列1,crefcol2 as 外來鍵列2,crefcol3 as 外來鍵列3,pk_table_owner as 主鍵表模式,fk_table_owner as 外來鍵表模式 from test_ref
drop table test_ref
今早,她又在網上,找我問關於外來鍵的問題:
關於外來鍵的一些疑問:
示例表1:create table 表1(表1欄位1 int not null,表1欄位2 char(20),表1欄位3 int not null,primary key(表1欄位1,表1欄位3))
資料1:外來鍵中列的數量必須與被引用表的主鍵中的列數相等
資料2:主鍵中的部份列或所有列可形成一個外來鍵.(資料來源:SQL完全知識手冊第四版)
疑問1:資料1與資料2是不是相矛盾啊? 測試結果表明,資料1是正確的,資料2不知如何測試??
疑問2:按資料2意思,就是說允許作為複合主鍵的若干列中的其中某一個列也可以形成一個外來鍵?也就是說,作為一個外來鍵可以引用主鍵中所有
      的主鍵組成列,也可以僅引用其中部份主鍵組成列???如果是這樣,當被引用表中主鍵為兩列時(即複合主鍵),如何建立並定義外來鍵,引
      用的其主鍵中的部份列?
例如:create table 表3(表3欄位1 int not null primary key,表3欄位2 char(20),表3欄位3 char(20),表3欄位4 int not null,
表3欄位5 int not null, foreign key(表3欄位4) references 表1(表1欄位1))
結果出錯,錯誤提示:在被引用表 '表1' 中沒有與外來鍵 'FK__表3__表3欄位4__20CCCE1C' 的引用列的列表匹配的主鍵或候選鍵。
疑問3:當外來鍵引用的是複合主鍵時,如下:
create table 表2(表2欄位1 int not null primary key,表2欄位2 char(20),表2欄位3 char(20),表2欄位4 int not null,
表2欄位5 int not null, foreign key(表2欄位5,表2欄位4) references 表1(表1欄位1,表1欄位3))
這種情況下:被引用的表1中的 表1欄位1 對應的是 所定義外來鍵的 表2欄位5
                 而表1中的 表1欄位3 對應的是 所定義外來鍵的 表2欄位4
           是應該理解成 表1欄位1 列 僅對應 表2欄位5 列  嗎?? 或者應該如何理解這種一個外來鍵引用多個列時的對應關係??

解題意義:如果資料1是正確的且資料2是錯誤的,那就說明,在關係查詢中,只需要查詢出被外來鍵引用的主鍵約束名稱,然後透過查詢主鍵名稱
即可得出被引用的表名及列名.如果資料2的情形成立的話.那麼,就無法透過查詢主鍵約束名來準確的得出被外來鍵引用的表名及列名了.
我的答案是:
1、問題中的第一點和第二點並不矛盾,關鍵是第二點裡指的是外來鍵表的主鍵
2、外來鍵可以包含多個列,但與它所引用的逐漸列數要一致。
而後她給我發了昨晚她整理的成果:
select a.name AS 外來鍵約束名,a.id AS 外來鍵ID,a.parent_obj AS 所屬表ID,c.table_name AS 所屬表名,c.column_name AS 定義該外來鍵的列名,
b.unique_constraint_name AS 被引用的主鍵名稱,d.table_name AS 被引用的表名
from sysobjects AS a,INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b,INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c,
INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS d
where a.name=b.constraint_name and a.name=c.constraint_name and b.constraint_name=c.constraint_name
and b.unique_constraint_name=d.constraint_name
and a.xtype = 'F' and a.parent_obj=object_id ('表名')--查詢指定表中的外來鍵關係結構
真是個很能鑽研的一個人,她成天也不睡覺,也不困啊。
網友修改後的查詢外來鍵的語句:
select aa.*,bb.column_name AS 被引用列名,bb.ordinal_position AS 被引用列位
from (select a.name AS 外來鍵約束名,a.id AS 外來鍵ID,a.parent_obj AS 所屬表ID,c.table_name AS 所屬表名,
c.column_name AS 定義該外來鍵的列名,c.ordinal_position AS 所屬列位,b.unique_constraint_name AS 被引用的主鍵名稱,d.table_name AS 被引用的表名
from sysobjects AS a,INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b,INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c,
INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS d
where a.name=b.constraint_name and a.name=c.constraint_name and b.constraint_name=c.constraint_name
and b.unique_constraint_name=d.constraint_name
and a.xtype = 'F' and a.parent_obj=object_id ('表名')) AS aa,INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS bb
where aa.被引用的主鍵名稱=bb.constraint_name and aa.所屬列位=bb.ordinal_position--指定表名,查詢外來鍵關係
又在網上看到了網友的奮鬥成果,雖然算不上很難,但也是比較麻煩,貼一下吧,獲取表check約束資訊的查詢:
SELECT sysobjects.name CHECK約束名, sysobjects.status 附加屬性值, sysconstraints.constid CHECK約束ID,
       object_name (sysconstraints.id) 所屬表名, sysconstraints.colid 所屬欄位ID, syscomments.text AS CHECK約束值,
       case when sysconstraints.colid=0 then '是'else '否' end AS 是否為表級約束
FROM sysobjects, sysconstraints, syscomments
WHERE xtype = 'c' AND sysobjects.id = sysconstraints.constid AND sysconstraints.constid = syscomments.id

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8484829/viewspace-605585/,如需轉載,請註明出處,否則將追究法律責任。

相關文章