【问题标题】:SQL JOIN to find mismatchesSQL JOIN 查找不匹配项
【发布时间】:2019-12-29 03:12:59
【问题描述】:

我有两个表,为简单起见命名 products1 和 products2,具有相同的架构:

(
  id int,
  name varchar(255),
  UNIQUE (id, name)
)

从技术上讲,它来自一个更复杂的架构,但我这样简化了它。 我需要和他们一起找出不匹配的地方。

说 products1 包含(1, "name1") and (1, "name11"), and (3, "name3")

products2 包含(1, "name1") and (1, "name11"), and (3, "name33"), and (4, "name4")

需要加入它们以查找名称中的不匹配,例如在上述情况下,不匹配将是(id, old_name, new_name) = (3, "name3", "name33")。不匹配是在两个表中都存在但名称不匹配的那些。因此,id=4 的记录不被视为不匹配。

我做了一个join,但是由于一个id可以有多个名字,结果有点出乎意料:

select p1.id, p1.name as old_name, p2.name as new_name
from products1 p1 join products2 p2 on p1.id = p2.id and p1.name <> p2.name

当 products1 中的 (1, "name1") 与 products2 中的 (1, "name11") 匹配时,它输出为不匹配。所以我总共有三个不匹配:

(id, old_name, new_name) = (1, "name1", "name11"), (1, "name11", "name1"), (3, "name3", "name33")

但是,products1 中的另一行已与 products2 中的该行匹配,因此不应将其视为不匹配。我想要实现的只是将(3, "name3", "name33") 输出为不匹配。 id = 1 的其他行不应不匹配。

如何通过查询实现这一点?

注意:找到运行多个查询,因为这将在 spark/scala 中作为多个步骤运行。

【问题讨论】:

    标签: sql scala apache-spark join


    【解决方案1】:

    如果你想使用纯 sql,这听起来像是 not exists 的工作。 编辑: OP更新后:

    select
    p2.*
    from
    products2 p2
    inner join products1 p1
        on p2.id = p1.id
    where not exists
    (select * from products1 p3
     where p3.id = p2.id
     and p3.name = p2.name)
    

    还有更新的dbfiddle

    【讨论】:

    • 抱歉刚刚添加了问题的更新。忘了提一个条件。
    • @Simo,做了一些更新,看看是否适合你。
    【解决方案2】:

    另一种选择是使用left join

    select p2.*
    from products2 p2
    left outer join products1 p1 on p2.id=p1.id and p2.name=p1.name
    where p1.id is null
    

    【讨论】:

    • 刚刚通过添加一个条件更新了问题(在帖子的末尾)。你能更新你的答案吗?
    【解决方案3】:
    select p1.id, p1.name, p2.name as name2 from
    p1 join p2
    on p1.id =p2.id and p1.name <> p2.name
    

    得到

    id  name    name2
    3   name3   name33
    

    create table p1 (  id int,  name varchar(255));
    create table p2 (  id int,  name varchar(255));
    insert into p1 (id, name) values (1, 'name1'),(2, 'name11'), (3, 'name3');
    insert into p2 (id, name) values (1, 'name1'),(2, 'name11'), (3, 'name33'),(4, "name4");
    

    http://sqlfiddle.com/#!9/36806f/2

    【讨论】:

    • Pete,name11 的 id 仍应为 1,而不是 2。主要问题在于 id 可以有多个名称,
    【解决方案4】:

    以下生成仅在一个 id 上的名称列表,但其 id 具有两个名称:

    select id, name, max(which)
    from (select p12.*,
                 min(which) over (partition by id) as min_which,
                 max(which) over (partition by id) as max_which
          from ((select p1.id, p1.name, 1 as which
                 from products1 p1
                ) union all
                (select p2.id, p2.name, 2 as which
                 from products2 p2
                )
               ) p12
         ) p12
    where min_which = 1 and max_which = 2  -- id in both tables
    group by id, name
    having min(which) = max(which)  -- but name only in one table;
    

    您的示例数据有点有限。我不确定每个 id 的单行会是什么样子,并且有更多的不匹配。

    【讨论】:

      【解决方案5】:

      在三个查询中:

      1. 您现在的查询(保存为名为“all”的表)
      2. 按 id 对“全部”进行分组,并仅保存在名为“正确”的表中恰好有一行的那些
      3. 从“all”中选择所有行,其中它们的 id 存在于“正确”中。

      第一个查询(将结果保存为表“all”):

      SELECT p1.id, p1.name AS old_name, p2.name AS new_name
      FROM products1 p1
      JOIN products2 p2 ON p1.id = p2.id
      WHERE p1.name <> p2.name
      

      第二次查询(将结果另存为“正确”表):

      SELECT id, COUNT(id) AS sum 
      FROM all 
      GROUP BY id 
      HAVING sum = 1
      

      最终查询:

      SELECT all.id, old_name, new_name 
      FROM all 
      JOIN correct ON all.id = correct.id
      

      输出:

      +---+--------+--------+
      | id|old_name|new_name|
      +---+--------+--------+
      |  3|   name3|  name33|
      +---+--------+--------+
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-05
        • 2015-06-16
        • 2013-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-16
        • 2012-03-10
        相关资源
        最近更新 更多