Sql 在数据库中搜索并反向工程外键关系,但不定义外键
我继承了一个非常古老的数据库,它有大约100个表。通过查看表,我知道存在外键关系,但我还确定数据库中实际上没有定义任何关系。此外,没有一致的命名约定 我试着通过查看表和尝试连接来解决这个问题,但这很费时,我没有那么多时间。所以现在我正在研究一些自动化的想法 有没有人试图在数据库上运行查询以查找外键 我对这个问题的一般逻辑的看法是: 对于每个表: 如果它有主键,请检查该键名是否存在于所有其他表中。如果是,请检查两组ID之间是否存在高百分比匹配。如果是,则将其作为潜在的FK关系输出。指定是一对一还是一对多 如果其他表中不存在相同的名称,请尝试在所有表中搜索数据类型完全相同的字段。尝试查看两组ID中是否存在高百分比匹配。如果是,则将其作为潜在的FK关系输出。指定是一对一还是一对多 我知道这可能会导致很多误报,但这比手动搜索要好 我的逻辑在这里是合理的,还是我在尝试自动搜索时完全偏离了基准 我的最终目标是生成一个ER图,在构建一些新查询时可以使用它 使用MSSQL让我们查找对:Sql 在数据库中搜索并反向工程外键关系,但不定义外键,sql,sql-server,foreign-keys,erd,Sql,Sql Server,Foreign Keys,Erd,我继承了一个非常古老的数据库,它有大约100个表。通过查看表,我知道存在外键关系,但我还确定数据库中实际上没有定义任何关系。此外,没有一致的命名约定 我试着通过查看表和尝试连接来解决这个问题,但这很费时,我没有那么多时间。所以现在我正在研究一些自动化的想法 有没有人试图在数据库上运行查询以查找外键 我对这个问题的一般逻辑的看法是: 对于每个表: 如果它有主键,请检查该键名是否存在于所有其他表中。如果是,请检查两组ID之间是否存在高百分比匹配。如果是,则将其作为潜在的FK关系输出。指定是一对一还是
SELECT * FROM
information_schema.columns cl
INNER JOIN
information_schema.columns cr
ON
cl.table_name < cr.table_name AND
cl.data_type = cr.data_type
如果您运行此SQL,它将生成一个结果网格,其中每行都有一个SQL—将其复制到网格中,并将其粘贴回查询编辑器中,删除最终的UNION ALL,然后运行它
在我相当小的数据库中,有90个表,每个表中约有8列,它生成了62000个它想做的组合;小心使用。。或者在备份服务器上运行一晚,第二天再来多亏了Caius Jard的出色解决方案。我对它进行了扩展,以根据我的需要进行定制。对于感兴趣的人,这里是:
-- Setup types to ignore
DECLARE @ignore table (ignorefield varchar(20));
-- Note: Must ignore 'text', must also ignore any other blob data types used in db. Others are optional.
INSERT @ignore(ignorefield) values('char'),('datetime'),('money'),('image'),('bit'),('binary'),('text');
-- Write queries to find fields that are potential foreign keys
SELECT
REPLACE(REPLACE(REPLACE(REPLACE(
'SELECT ''{Ltable}.{Lcol}'' as lefty, ''{Rtable}.{Rcol}'' as righty, count(l.{Lcol}) as countLefty, count(r.{Rcol}) as countRighty, case when count(r.{Rcol}) = 0 then 0 else count(l.{Lcol})/count(r.{Rcol}) end as percenty
FROM {Ltable} l LEFT JOIN {Rtable} r ON l.{Lcol} = r.{Rcol} UNION ALL',
'{Ltable}', QUOTENAME(cl.table_name)),
'{Rtable}', QUOTENAME(cr.table_name)),
'{Lcol}', QUOTENAME(cl.column_name)),
'{Rcol}', QUOTENAME(cr.column_name))
FROM
information_schema.columns cl
INNER JOIN
information_schema.columns cr
ON
cl.table_name < cr.table_name AND
cl.data_type = cr.data_type
WHERE
cl.data_type NOT IN (SELECT ignorefield from @ignore)
AND cl.is_nullable = 'NO' -- Maybe remove for some db designs.
ORDER BY
cl.data_type ASC
不需要只是主键。您可以为一个唯一的约束设置关键帧。如果关系没有定义,您可以通过现有知识或探索数据来找出关系的唯一方式。SQL Server将不知道这些关系是什么。我每天都要处理这样的数据库;表中没有一个外键,其他表中通常不存在主键值;甚至那些可能成为候选人的人也会有孤立的行。我们如何知道存在什么样的关系?我们自己的文件,而不是供应商;不断更新的东西。远非理想,但1979年的DB会发生什么呢?好的一点:我站在正确的立场上@Dfundako这真的没有办法自动化。正如你所说的,你可能会得到假阳性。但你也很可能错过重要的关系,因为名字不同。在数据库中花费大量时间并进行探索大概是接近确定的唯一方法。这种类型的数据库需要部落知识,而获得这种知识的唯一途径就是时间。我不明白为什么有些东西不能自动化——写一些东西,在信息模式中挖掘。列在两个表中查找相同类型的列,通过左连接计算出它们在值中所占的百分比-计算左列和右列,看看从右/左得到的百分比,这是一个非常漂亮的嵌套替换语句。我喜欢。我没有想到要这么做。我的跑步成绩是2678538排。在备份上运行可能是个好主意好极了,他们在一些列名中有关键词。叹气感谢您的帮助,这应该很有趣。与递增的INT-id相比,GUID-id肯定是一个提升。我希望一个基于guid的数据库能够为所有真正相关的列显示一个很高的百分比,而不相关的列显示0%。。Incrmentin ints会更加混乱:祝你好运!
-- Setup types to ignore
DECLARE @ignore table (ignorefield varchar(20));
-- Note: Must ignore 'text', must also ignore any other blob data types used in db. Others are optional.
INSERT @ignore(ignorefield) values('char'),('datetime'),('money'),('image'),('bit'),('binary'),('text');
-- Write queries to find fields that are potential foreign keys
SELECT
REPLACE(REPLACE(REPLACE(REPLACE(
'SELECT ''{Ltable}.{Lcol}'' as lefty, ''{Rtable}.{Rcol}'' as righty, count(l.{Lcol}) as countLefty, count(r.{Rcol}) as countRighty, case when count(r.{Rcol}) = 0 then 0 else count(l.{Lcol})/count(r.{Rcol}) end as percenty
FROM {Ltable} l LEFT JOIN {Rtable} r ON l.{Lcol} = r.{Rcol} UNION ALL',
'{Ltable}', QUOTENAME(cl.table_name)),
'{Rtable}', QUOTENAME(cr.table_name)),
'{Lcol}', QUOTENAME(cl.column_name)),
'{Rcol}', QUOTENAME(cr.column_name))
FROM
information_schema.columns cl
INNER JOIN
information_schema.columns cr
ON
cl.table_name < cr.table_name AND
cl.data_type = cr.data_type
WHERE
cl.data_type NOT IN (SELECT ignorefield from @ignore)
AND cl.is_nullable = 'NO' -- Maybe remove for some db designs.
ORDER BY
cl.data_type ASC