ITPub博客

首页 > 数据库 > SQL Server > 关于网友的获取MSSQL外键信息的问题的探讨

关于网友的获取MSSQL外键信息的问题的探讨

原创 SQL Server 作者:sqysl 时间:2009-06-09 05:31:54 0 删除 编辑

昨晚,网友又提出了一个问题: 
求一个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/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
大学毕业至今,一直深耕于数据库领域20余载,擅长数据库优化、数据库分析诊断、数据库规划设计等,曾任职多家知名大型企业,多次独立承担并成功上线关键大型项目。

注册时间:2008-06-27

  • 博文量
    356
  • 访问量
    643170