2010-01-23 43 views
2

下面的查询根据4列中的值选择table_2中不存在的行。不匹配可能是由于一列或多列造成的。SQL帮助:查找哪些列导致不匹配

我想扩展查询来告诉我哪些列有不匹配的值,或者通过显示列名或其值。我可以在游标中做到这一点,但如果可能的话,宁愿在基于集合的操作中执行此操作。

SELECT i.agent , 
     i.agency , 
     i.customer , 
     i.Company 
FROM table_1 AS i 
WHERE NOT EXISTS (SELECT p.agent , 
          p.agency , 
          p.customer , 
          p.Company 
        FROM table_2 AS p 
        WHERE i.Agent = p.Agent 
          AND i.agency = p.Agency 
          AND i.customer = p.customer 
          AND i.Company = p.Company) 

更新: 我想这需要更多的细化。我们再补充一下,4列中有3列需要匹配。

+1

@Tony_Henrich:我觉得这可能很难。你能否澄清一下:说一行(代理和代理)或者(客户和公司)匹配 - 你想看什么? – 2010-01-23 00:13:34

+0

如果代理和代理商匹配,我想查看'客户,公司'或他们的价值。 – 2010-01-23 00:32:33

+0

我还是不明白......你能解释一下,你想像一个5岁的孩子一样完成什么?如果不是在查询方面,但在信息方面更好。 – jachguate 2010-01-23 01:23:13

回答

2

可以简化这个问题急剧如果您需要记录某些列匹配,或者至少从某些期望开始,应与匹配。换句话说,不要把这看作是不匹配的问题,重新定义它为部分匹配的问题。

假设您期望agentagency匹配,但customercompany可能不匹配。这并不难:

SELECT 
    i.agent, i.agency, i.customer, i.company, p.customer, p.company, 
    CASE 
     WHEN i.customer = p.Customer THEN 'Y' 
     ELSE 'N' 
    END AS matchescustomer, 
    CASE 
     WHEN i.company = p.Company THEN 'Y' 
     ELSE 'N' 
    END AS matchescompany 
FROM table1 i 
INNER JOIN table2 p 
    ON p.agent = i.agent 
    AND p.agency = i.agency 

如果你想检查其他部分匹配,只需重新排列列。而不是加入agentagency,加入agentcustomer,或其他。

如果你只想到了几个不同种类的部分匹配的,你可以写类似于上面的一个几个不同的查询,并把它们连同UNION(或UNION ALL如果你不介意重复)。换句话说:

SELECT (columns) 
FROM table1 i INNER JOIN table2 p 
    ON p.agent = i.agent AND p.agency = i.agency 
UNION 
SELECT (columns) 
FROM table1 i INNER JOIN table2 p 
    ON p.agent = i.agent AND p.customer = i.customer 

现在,如果你希望得到每一个可以想象的不匹配,那么这很快会失控,所以你可能要适应一个更加启发式方法,搜索部分匹配匹配至少一定数量的列(比如3)。然后,你可以最多限制obnoxiousness到的列数,你必须比较:

;WITH PartialMatches_CTE AS 
(
    SELECT i.agent AS iagent, p.agent AS pagent, ... (etc.) 
    FROM table1 i INNER JOIN table2 p ON p.agent = i.agent 
    UNION ALL 
    SELECT (...) FROM table1 INNER JOIN table2 ON p.agency = i.agency 
    UNION ALL 
    SELECT (...) FROM table1 INNER JOIN table2 ON p.company = i.company 
    ... and so on 
), 
ResolvedMatches_CTE AS 
(
    SELECT DISTINCT 
     iagent, pagent, iagency, pagency, ..., 
     CASE WHEN pagent = iagent THEN 'Y' ELSE 'N' END AS agentmatch, 
     CASE WHEN pagency = iagency THEN 'Y' ELSE 'N' END AS agencymatch, 
     ..., 
     (CASE WHEN pagent = iagent THEN 1 ELSE 0 END + 
     CASE WHEN pagency = iagency THEN 1 ELSE 0 END + 
     ...) AS MatchCount 
    FROM PartialMatches_CTE 
) 
SELECT * 
FROM ResolvedMatches_CTE 
WHERE MatchCount >= 3 

现在,说了这么多,有一两件事我不知道......

这两个数据表不是,偶然的,依次相关的,是吗?如中所示,table1中的第3行总是映射到表2中的第3行,但可能不匹配所有列?这是在黑暗中拍摄的,但如果确实如此,那么我们可以简化这种方式。否则,这里的最后一个查询应该可以做你想要的,而不会变成大部分不可维护的混乱。

请注意,对于所有这些查询,性能可能会很差。希望你的数据集不太大。 AFAIK没有简单的方法来真正优化这种事情。

+0

+1这肯定比我的解决方案更灵活。虽然有点难缠我的头。我猜'PartialMatches'列出了一列或多列上匹配的任何东西,然后'ResolvedMatches'表示每列是否匹配(Y或N)并且还计算匹配的数量。 'SELECT DISTINCT'摆脱所有重复。一个问题:如果你在第一个CTE而不是第二个CTE上选择了“SELECT DISTINCT”,会发生什么? – devuxer 2010-01-23 01:42:37

+0

@DanM:CTE并非绝对必要,他们只是为了便于阅读。第一个CTE获取部分匹配列表(1列或更多列),第二个将它们分类,最后一个查询过滤它们。在第一个CTE中使用'DISTINCT'不会对你有所帮助,但如果你在'Resolved'中取出'DISTINCT',并在'PartialMatches_CTE'中将每个'UNION ALL'改为'UNION',你都会得到相同的结果。我的直觉是,我写的版本会更快,但它们都会很慢。 – Aaronaught 2010-01-23 01:52:32

+0

另外,ResolvedMatches_CTE中的第一套'CASE'语句并不是严格必要的,要么是所有你想要的都是不匹配的行。他们只是在那里帮助快速识别哪些列不匹配,以便他们不必盯着8列或更多列并进行可视化比较。 – Aaronaught 2010-01-23 01:53:29

0

这是明确的吗?如果p中存在[1,2,3,4]和[5,2,3,5],则i中的[1,2,3,5]与列[1,2,3,4]不匹配d和列a中的[5,2,3,5]不匹配。或者你会声称这是由于d和a而导致的不匹配?

1

正如其他人所说,这个问题需要更多的定义。

比方说你在表1中的对象:

  1. 又大又红,甜苹果
  2. 小,绿色,酸苹果
  3. 中,橙,甜桃
  4. 中,橙色,酸橘

,并在表2中的对象:

  1. 小,红,甜梅
  2. 大,红,甜苹果
  3. 小,绿色,酸苹果
  4. 小,橙色,甜桔

现在,让我们通过表1 :

  1. 又大又红,甜苹果在表2
  2. 小,绿色,苹果馅饼比赛第2项没有匹配 - 哪个列不匹配?
    • 表2,第1项 - 大小,颜色,味道,水果
    • 表2,第1项不匹配 - 不匹配的大小,颜色,味道
    • ...
    • ...
  3. (也有不匹配)
    • ...
    • ...
    • ...
    • ...
  4. (也有不匹配)
    • ...
    • ...
    • ...
    • ...

,你可以看,这很快就成了一个指数问题。每个列表中只有四个项目,您有12个不匹配的对列出列。如果您有10万件产品和10,000种不匹配产品,则必须列出1亿双。

如果您重新定义查询,以便仅列出一个属性(列)上不同的项目,那么它可能会更容易一些。事情是这样的:

-- warning untested code -- 

     SELECT 'agent' AS MismatchedColumn , 
       p.agent AS MismatchedValue , 
       i.agent , 
       i.agency , 
       i.customer , 
       i.company 
      FROM table_1 AS i 
LEFT OUTER JOIN table_2 AS p 
      ON i.agent != p.agent 
       AND i.agency = p.agency 
       AND i.customer = p.customer 
       AND i.company = p.company 
      UNION 
     SELECT 'agency' AS MismatchedColumn , 
       p.agency AS MismatchedValue , 
       i.agent , 
       i.agency , 
       i.customer , 
       i.company 
      FROM table_1 AS i 
LEFT OUTER JOIN table_2 AS p 
      ON i.agent = p.agent 
       AND i.agency != p.agency 
       AND i.customer = p.customer 
       AND i.company = p.company 
      UNION 
     SELECT 'customer' AS MismatchedColumn , 
       p.customer AS MismatchedValue , 
       i.agent , 
       i.agency , 
       i.customer , 
       i.company 
      FROM table_1 AS i 
LEFT OUTER JOIN table_2 AS p 
      ON i.agent = p.agent 
       AND i.agency = p.agency 
       AND i.customer != p.customer 
       AND i.company = p.company 
      UNION 
     SELECT 'company' AS MismatchedColumn , 
       p.company AS MismatchedValue , 
       i.agent , 
       i.agency , 
       i.customer , 
       i.company 
      FROM table_1 AS i 
LEFT OUTER JOIN table_2 AS p 
      ON i.agent = p.agent 
       AND i.agency = p.agency 
       AND i.customer = p.customer 
       AND i.company != p.company 

我相信这会列出所有表1匹配所有,但一列,在表2

+0

我在我的问题中增加了另一个要求。 – 2010-01-23 00:41:59

+0

我猜对了:) – devuxer 2010-01-23 01:01:04

+0

根据情况给出了很好的答案...当然,如果有人决定他们想检索仅匹配2列的记录,那么你就会被洗脑。 ;) – Aaronaught 2010-01-23 01:18:41