2

我必须维护一个设计非常糟糕的可怕遗留数据库。所有的表都有超过 100 列 - 一个有 650 列。数据库非常非规范化,我发现通常相同的数据在同一行的几列中表示。

例如,以下是其中一个表的列示例:

[MEMBERADDRESS] [varchar](331) NULL,
[DISPLAYADDRESS] [varchar](max) NULL,

[MEMBERINLINEADDRESS] [varchar](max) NULL,
[DISPLAYINLINEADDRESS] [varchar](250) NULL,

[__HISTISDN] [varchar](25) NULL,
[HISTISDN] [varchar](25) NULL,
[MYDIRECTISDN] [varchar](25) NULL,
[MYISDN] [varchar](25) NULL,

[__HISTALT_PHONE] [varchar](25) NULL,
[HISTALT_PHONE] [varchar](25) NULL,

事实证明,MEMBERADDRESSDISPLAYADDRESS中所有行的值都相同。我在这里展示的其他领域集群也是如此。

手动识别所有此类情况将非常困难且耗时。是否可以创建一个查询来确定两个字段在表的每一行中是否具有相同的值?

如果没有,是否有任何现有工具可以帮助我识别这些问题?

4

2 回答 2

2

我看到有两种方法可以简化这个查询:

  • 编写一个脚本来生成您的查询- 为您的脚本提供表的名称和可疑列,并让它生成一个查询来检查每对列的相等性。这是在像您这样的情况下实施的最快方法。
  • 编写一个“规范化”您的数据的查询,并对其进行搜索- 将查询自行连接到自身,然后过滤掉重复项。

这是第二种方法的快速说明:

SELECT id, name, val FROM (
    SELECT id, MEMBERADDRESS as val,'MEMBERADDRESS' as name FROM MyTable
    UNION ALL
    SELECT id, DISPLAYADDRESS as val,'DISPLAYADDRESS' as name FROM MyTable
    UNION ALL
    SELECT id, MEMBERINLINEADDRESS as val,'MEMBERINLINEADDRESS' as name FROM MyTable
    UNION ALL
    ...
) first
JOIN (
    SELECT id, MEMBERADDRESS as val,'MEMBERADDRESS' as name FROM MyTable
    UNION ALL
    SELECT id, DISPLAYADDRESS as val,'DISPLAYADDRESS' as name FROM MyTable
    UNION ALL
    SELECT id, MEMBERINLINEADDRESS as val,'MEMBERINLINEADDRESS' as name FROM MyTable
    UNION ALL
    ...
) second ON first.id=second.id AND first.value=second.value

100 列有很多手动工作(至少它不会像N^2第一种方法那样增长,但仍然需要大量手动输入)。您最好生成与UNION ALL使用小脚本相关的选择。

于 2013-03-27T17:24:20.500 回答
1

以下方法用于unpivot创建三元组。它做了一些假设:值不为空;每行都有一个id;并且列具有兼容的类型。

select t.which, t2.which 
from (select id, which, value
      from MEMBERADDRESS
      unpivot (value for which in (<list of columns here>)) up
     ) t full outer join
     (select id, which, value
      from MEMBERADDRESS
      unpivot (value for which in (<list of columns here>)) up
     ) t2
     on t.id = t2.id and t.which <> t2.which
group by t.which, t2.which
having sum(case when t.value = t2.value then 1 else 0 end) = count(*)

它通过创建一个包含三列的新表来工作:id、列和列中的值。然后它对 id (以将比较保持在一行内)和 value (以获取匹配值)进行自连接。这种自联接应该始终匹配,因为查询的两半中的列是相同的。

然后having计算给定列对两侧相同的值的数量。当所有这些都相同时,则匹配成功。

您也可以省略该having子句并使用以下内容:

select t.which, t2.which, sum(case when t.value = t2.value then 1 else 0 end) as Nummatchs,
       count(*) as NumRows

以获得更完整的信息。

于 2013-03-27T17:32:35.587 回答