Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 在数据库中搜索并反向工程外键关系,但不定义外键_Sql_Sql Server_Foreign Keys_Erd - Fatal编程技术网

Sql 在数据库中搜索并反向工程外键关系,但不定义外键

Sql 在数据库中搜索并反向工程外键关系,但不定义外键,sql,sql-server,foreign-keys,erd,Sql,Sql Server,Foreign Keys,Erd,我继承了一个非常古老的数据库,它有大约100个表。通过查看表,我知道存在外键关系,但我还确定数据库中实际上没有定义任何关系。此外,没有一致的命名约定 我试着通过查看表和尝试连接来解决这个问题,但这很费时,我没有那么多时间。所以现在我正在研究一些自动化的想法 有没有人试图在数据库上运行查询以查找外键 我对这个问题的一般逻辑的看法是: 对于每个表: 如果它有主键,请检查该键名是否存在于所有其他表中。如果是,请检查两组ID之间是否存在高百分比匹配。如果是,则将其作为潜在的FK关系输出。指定是一对一还是

我继承了一个非常古老的数据库,它有大约100个表。通过查看表,我知道存在外键关系,但我还确定数据库中实际上没有定义任何关系。此外,没有一致的命名约定

我试着通过查看表和尝试连接来解决这个问题,但这很费时,我没有那么多时间。所以现在我正在研究一些自动化的想法

有没有人试图在数据库上运行查询以查找外键

我对这个问题的一般逻辑的看法是:

对于每个表: 如果它有主键,请检查该键名是否存在于所有其他表中。如果是,请检查两组ID之间是否存在高百分比匹配。如果是,则将其作为潜在的FK关系输出。指定是一对一还是一对多

如果其他表中不存在相同的名称,请尝试在所有表中搜索数据类型完全相同的字段。尝试查看两组ID中是否存在高百分比匹配。如果是,则将其作为潜在的FK关系输出。指定是一对一还是一对多

我知道这可能会导致很多误报,但这比手动搜索要好

我的逻辑在这里是合理的,还是我在尝试自动搜索时完全偏离了基准

我的最终目标是生成一个ER图,在构建一些新查询时可以使用它

使用MSSQL

让我们查找对:

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