SQL基于表B数据组合(去重复)表A?

时间:2018-04-21 10:56:26

标签: mysql sql postgresql sqlite

如何编写SQL(SQLite3,postgres或MySQL) 基于表B数据组合(去重复)表A?

给定拥有电话号码的人(表:联系人)(表:电话), 我想使用电话号码删除重复的联系人。

在这个例子中,公司在那里进行澄清, 即使实际数据可能没有列出相同的公司 根据电话号码,人是一样的。

注意,在这个例子中,有两个不同的贝蒂,但是 两个查尔斯是同一个人,应该合并。

此外,Ashok和Dale有一个共同的电话号码,因为他们 为同一家公司工作,但不是同一个人。

Table: contacts
===============
id      name      company
1       Ashok     Alpha Co.
2       Betty     Beta Inc.
3       Charles   Cain LLC.          <---|
4       Betty     Delta Corp.            |-- same person
5       Charles   Cain LLC.          <---|
6       Dale      Alpha Co.

Table: phones
============
id      phone_number    contact_id
1       (111) 123-1111  1
2       (111) 123-2222  1
3       (111) 123-3333  1
4       (111) 123-4444  1
5       (222) 456-1111  2
6       (222) 456-2222  2
7       (333) 789-1111  3
8       (333) 789-2222  3
9       (333) 789-3333  3
10      (333) 789-4444  3
11      (444) 456-7777  4
12      (444) 456-8888  4
13      (555) 789-5555  5
14      (333) 789-2222  5
15      (111) 123-3333  6

加入表格给出:

SELECT      c.id, c.name, c.company, p.phone_number, p.contact_id
FROM        contacts as c
INNER JOIN  phones as p
ON          c.id = p.contact_id

c.id    c.name      c.company       p.phone         p.contact_id
1       Ashok       Alpha Co.       (111) 123-1111  1
1       Ashok       Alpha Co.       (111) 123-2222  1
1       Ashok       Alpha Co.       (111) 123-3333  1
1       Ashok       Alpha Co.       (111) 123-4444  1
2       Betty       Beta Inc.       (222) 456-1111  2
2       Betty       Beta Inc.       (222) 456-2222  2
3       Charles     Cain LLC.       (333) 789-1111  3
3       Charles     Cain LLC.       (333) 789-2222  3
3       Charles     Cain LLC.       (333) 789-3333  3
3       Charles     Cain LLC.       (333) 789-4444  3
4       Betty       Delta Corp.     (444) 456-7777  4
4       Betty       Delta Corp.     (444) 456-8888  4
5       Charles     Cain LLC.       (555) 789-5555  5
5       Charles     Cain LLC.       (333) 789-2222  5
6       Dale        Alpha Co.       (111) 123-3333  6

所以我想的是我想要遍历所有 对于电话号码,请获取每个电话号码的所有联系人 这些数字,检查名称是否相同,如果 他们删除重复的联系人并更改contact_ids 在电话号码上。

所以结果如下:

Table: contacts
===============
id      name      company
1       Ashok     Alpha Co.
2       Betty     Beta Inc.
3       Charles   Cain LLC.
4       Betty     Delta Corp.       <-- Note the duplicate Charles (5) is removed
6       Dale      Alpha Co.

Table: phones
============
id      phone_number    contact_id
1       (111) 123-1111  1
2       (111) 123-2222  1
3       (111) 123-3333  1
4       (111) 123-4444  1
5       (222) 456-1111  2
6       (222) 456-2222  2
7       (333) 789-1111  3
8       (333) 789-2222  3
9       (333) 789-3333  3
10      (333) 789-4444  3
11      (444) 456-7777  4
12      (444) 456-8888  4
13      (555) 789-5555  3         <-- Note the contact_id is updated
15      (111) 123-3333  6         <-- Note the duplicate phone number (14) is removed

c.id    c.name      c.company       p.phone         p.contact_id
1       Ashok       Alpha Co.       (111) 123-1111  1
1       Ashok       Alpha Co.       (111) 123-2222  1
1       Ashok       Alpha Co.       (111) 123-3333  1
1       Ashok       Alpha Co.       (111) 123-4444  1
2       Betty       Beta Inc.       (222) 456-1111  2
2       Betty       Beta Inc.       (222) 456-2222  2
3       Charles     Cain LLC.       (333) 789-1111  3
3       Charles     Cain LLC.       (333) 789-2222  3
3       Charles     Cain LLC.       (333) 789-3333  3
3       Charles     Cain LLC.       (333) 789-4444  3
4       Betty       Delta Corp.     (444) 456-7777  4
4       Betty       Delta Corp.     (444) 456-8888  4
3       Charles     Cain LLC.       (555) 789-5555  3
6       Dale        Alpha Co.       (111) 123-3333  6

2 个答案:

答案 0 :(得分:1)

以下假设您的问题与您说的一样简单。换句话说,它只是寻找相同的联系人对,而不是遍历可能更复杂的图表。

如果您说任何两个具有相同电话号码的联系人(无论他们有多少)和相同的名称相同,那么您可以使用以下方式找到它们:

with cp as (
      select c.*, p.phone_number
      from contacts c join
           phones p
           on c.id = p.contact_id
     )
select distinct cp.id as id1, cp2.id as id2
from cp join
     cp cp2
     on cp.phone_number = cp2.phone_number and cp.name = cp2.name and
        cp.id <> cp2.id;

据推测,您希望保留第一次联系。所以,让我们使用聚合代替。在此

select min(cp.id) as id1, cp2.id as id2
from cp join
     cp cp2
     on cp.phone_number = cp2.phone_number and cp.name = cp2.name and
         cp.id < cp2.id
group by cp2.id;

这会产生成对的联系ID。我们希望保留第一个并删除第二个。

现在,如果我们假设重复只有一个深,那么我们可以将其合并到delete

with cp as (
      select c.*, p.phone_number
      from contacts c join
           phones p
           on c.id = p.contact_id
     )
delete from contacts
    where id in (select cp2.id
                 from cp join
                      cp cp2
                      on cp.phone_number = cp2.phone_number and cp.name = cp2.name and
                         cp.id < cp2.id
                );

group by实际上不需要in。)。

注意:这在MySQL中不起作用,其中需要使用JOIN来表示等效逻辑,并且不支持CTE。

答案 1 :(得分:0)

我认为最简单的方法是分三步:

  1. 执行标识重复记录的查询,选择冗余记录并将其保存到临时表
  2. 删除此临时表中的联系人
  3. 删除此临时表中的电话
  4. 可以使用此查询(演示:http://sqlfiddle.com/#!9/a20149/6

    完成第一步
    -- CREATE TABLE TEMP_TABLE AS
    SELECT p.id as id_phone,
           p.phone_number,
           p.contact_id,
           c.id as id_contact,
           c.name,
           c.company
    FROM phones p
    JOIN contacts c
    ON p.contact_id = c.id
    WHERE EXISTS (
      SELECT 'Anythng' 
      FROM phones p1
      JOIN contacts c1
      ON p1.contact_id = c1.id
      WHERE p1.phone_number = p.phone_number
        AND c1.name = c.name
        AND c.id < c1.id 
    );
    
    | id_phone |   phone_number | contact_id | id_contact |    name |   company |
    |----------|----------------|------------|------------|---------|-----------|
    |        8 | (333) 789-2222 |          3 |          3 | Charles | Cain LLC. |
    

    然后是第2步和第3步:

    DELETE contacts WHERE ID IN (SELECT id_contact FROM temp_table);
    DELETE phones WHERE ID IN (SELECT id_phone FROM temp_table);