如何将一个Master表与几个子表进行比较

时间:2014-01-23 01:53:59

标签: sql sql-server tsql

我有一个主表(PO_BreakOutAll),其中有大约3000行,只有两列(PO_IDPO_LN_NO)组成了主键。我还有几个其他的表,每个表都有一个来自主表的数据子集(或者它应该是这样)。所有表都与主表相同。

所有表都有这个确切的架构:

PO_ID     char(5) PK
PO_LN_NO  int     PK

我需要进行两种不同类型的比较以进行验证并查找重复项。

首先确保主表中的每一行都存在于其他子表中的一个且仅存在一个子表中。

其次,我需要确保在任何子表中都没有重复行。同一行可以存在于两个或多个子表中,我需要找到它们。

我可以在单独的查询中执行每个表,但还没有弄清楚如何编写一个查询来同时比较所有子表。

这是我到目前为止所做的,但它不起作用:

SELECT a.PO_ID as all_PO,
       a.PO_LN_NO,
       c.PO_ID as Cummings_PO,
       c.PO_LN_NO,
       f.PO_ID as filter_PO,
       f.PO_LN_NO,
       fo.PO_ID as fixedObl_PO,
       fo.PO_LN_NO
FROM 
       PO_BreakOutAll   a
       LEFT OUTER JOIN
       PO_Cummins       c   ON (c.PO_ID = a.PO_ID AND c.PO_LN_NO = a.PO_LN_NO)
       LEFT OUTER JOIN
       PO_Filters       f   ON (f.PO_ID = a.PO_ID AND f.PO_LN_NO = a.PO_LN_NO)
       LEFT OUTER JOIN
       PO_FixedOblig    fo  ON (fo.PO_ID = a.PO_ID AND fo.PO_LN_NO = a.PO_LN_NO)

2 个答案:

答案 0 :(得分:1)

我不会将join用于此;我会用union all。这是一种计算记录如何在表间重叠的方法:

select isAll, isCummins, isFilters, isOblig, count(*)
from (select PO_ID, PO_LN_NO, sum(isAll) as isAll, sum(isCummins) as isCummins,
             sum(isFilters) as isFilters, sum(isOblig) as isOblig
      from ((select PO_ID, PO_LN_NO, 1 as isAll, 0 as isCummins, 0 as isFilters, 1 as isOblig
             from PO_BreakOutAll
            ) union all
            (select PO_ID, PO_LN_NO, 0, 1, 0, 0
             from PO_Cummins
            ) union all
            (select PO_ID, PO_LN_NO, 0, 0, 1, 0
             from PO_Filters
            ) union all
            (select PO_ID, PO_LN_NO, 0, 0, 0, 1
             from PO_FixedOblig
            )
           ) t
      group by PO_ID, PO_LN_NO
     ) t
group by isAll, isCummins, isFilters, isOblig;

如果要查找未通过测试的行,只需使用带有where条件的子查询:

      select PO_ID, PO_LN_NO, sum(isAll) as isAll, sum(isCummins) as isCummins,
             sum(isFilters) as isFilters, sum(isOblig) as isOblig
      from ((select PO_ID, PO_LN_NO, 1 as isAll, 0 as isCummins, 0 as isFilters, 1 as isOblig
             from PO_BreakOutAll
            ) union all
            (select PO_ID, PO_LN_NO, 0, 1, 0, 0
             from PO_Cummins
            ) union all
            (select PO_ID, PO_LN_NO, 0, 0, 1, 0
             from PO_Filters
            ) union all
            (select PO_ID, PO_LN_NO, 0, 0, 0, 1
             from PO_FixedOblig
            )
           ) t
      group by PO_ID, PO_LN_NO
      having sum(isAll) <> 1 or
             (sum(isAll) = 1 and (sum(isCummins) + sum(isFilters) + sum(isOblig) <> 1)
             );

答案 1 :(得分:1)

我认为@gordon linoff有一个整体解决方案。如果您想使用CTE范例,可以使用example based on your Fiddle来回答重复的问题:

WITH CTE (PO_ID,PO_LN_NO,TableName) AS

(SELECT 
 PO_ID,
 PO_LN_NO,
 'Cummings' as TableName


 FROM PO_Cummins
 UNION ALL
 SELECT 
 PO_ID,
 PO_LN_NO,
 'Filters' as TableName

 FROM PO_Filters
 UNION ALL
 SELECT 
 PO_ID,
 PO_LN_NO,
 'Office' as TableName

 FROM PO_Office )

SELECT
  PO_BreakOutAll.PO_ID, 
  PO_BreakOutAll.PO_LN_NO,
  CHILD_DATA.TABLENAME AS DUP_TABLENAME
FROM
  PO_BreakOutAll
INNER JOIN (
  SELECT PO_ID, PO_LN_NO, COUNT(1) AS DUP_COUNTER
  FROM CTE
  GROUP BY PO_ID, PO_LN_NO
  HAVING COUNT(1) > 1 
  ) DUPS ON DUPS.PO_ID = PO_BreakOutAll.PO_ID AND DUPS.PO_LN_NO = PO_BreakOutAll.PO_LN_NO
INNER JOIN (
  SELECT PO_ID, PO_LN_NO, TABLENAME
  FROM CTE
  ) CHILD_DATA
  ON CHILD_DATA.PO_ID = PO_BreakOutAll.PO_ID AND CHILD_DATA.PO_LN_NO = PO_BreakOutAll.PO_LN_NO
ORDER BY PO_ID, PO_LN_NO, DUP_TABLENAME