从两个表中选择行并排除两个表中存在的主键

时间:2016-03-01 20:18:33

标签: mysql sql database

我有两个服务提供商表,providersproviders_cleanproviders包含数千个格式很差的数据提供商,providers_clean只有一些提供商仍然存在于'脏'表中。

我希望系统使用此数据在用户“清理”数据时保持正常运行,因此我希望能够选择已经“清理”的所有行以及仍然'脏',同时排除任何与'干净'相同的'脏'结果。

如何从providers_clean表中选择与providers表中所有提供商合并的所有提供商,并排除那些已经“清理”的提供商

我试过了:

SELECT * FROM providers WHERE NOT EXISTS (SELECT * FROM providers_clean WHERE providers_clean.id = providers.id)

它给了我providers排除'干净'的所有'脏'结果,但是如何重写查询现在合并来自providers_clean的所有'干净'?

这是我正在尝试做的直观表达:

Clean Table

+----+-------------------+
| ID |       Name        |
+----+-------------------+
|  1 | Clean Provider 1  |
|  4 | Clean Provider 4  |
|  5 | Clean Provider 5  |
+----+-------------------+


Dirty Table
+----+------------------+
| ID |       Name       |
+----+------------------+
|  1 | Dirty Provider 1 |
|  2 | Dirty Provider 2 |
|  3 | Dirty Provider 3 |
|  4 | Dirty Provider 4 |
|  5 | Dirty Provider 5 |
+----+------------------+


Desired Result

+----+------------------+
| ID |       Name       |
+----+------------------+
|  1 | Clean Provider 1 |
|  2 | Dirty Provider 2 |
|  3 | Dirty Provider 3 |
|  4 | Clean Provider 4 |
|  5 | Clean Provider 5 |
+----+------------------+

由于

更新

这是有效的,但是,有更有效的方法来编写此查询吗?

SELECT providers.id AS id, 
CASE 
  WHEN 
   providers_clean.id IS NOT NULL 
  THEN 
   providers_clean.provider_name
  ELSE 
   providers.provider_name
END AS pname,

CASE 
  WHEN 
   providers_clean.id IS NOT NULL 
  THEN 
   providers_clean.phone
  ELSE 
   providers.phone
END AS pphone,

CASE 
  WHEN 
   providers_clean.id IS NOT NULL 
  THEN 
   providers_clean.website
  ELSE 
   providers.website
END AS pwebsite

FROM providers
  LEFT JOIN providers_clean ON providers_clean.id = providers.id
ORDER BY providers.id asc

3 个答案:

答案 0 :(得分:1)

好像你需要LEFT JOIN

SELECT COALESCE(pc.ID, p.ID), COALESCE(pc.Name, p.Name)
FROM providers AS p
LEFT JOIN providers_clean AS pc ON p.ID = pc.ID

这个查询本质上是做什么的:如果记录存在于' clean'然后选择这一个,否则从'脏'中选择一个。表

答案 1 :(得分:1)

,经常参考this 以及this关于JOIN如何工作的直观解释。

根据它们,你需要一个FULL OUTER JOIN,不包括两个表中的项目("外部不包括JOIN和#34;):

SELECT *
  FROM providers p
  FULL OUTER JOIN providers_clean pc
       ON pc.id = p.id
 WHERE p.id IS NULL OR pc.id IS NULL;

更新不幸的是,MySQL中没有FULL OUTER JOIN,所以你必须模仿它。我使用this回答来做到这一点:

select p.*
  from providers p left join providers_clean pc on pc.id = p.id
  where pc.id is null
union all
select pc.* 
  from providers p right join providers_clean pc on pc.id = p.id;

第一个SELECT是脏的,没有干净的副本,第二个SELECT只是干净的。

答案 2 :(得分:1)

你需要做一个从Dirty到Clean的外连接(因为Dirty所有行都是Clean,但反之亦然)

SELECT dirty.id AS id, 
CASE 
  WHEN clean.id IS NOT NULL THEN clean.name
  ELSE dirty.name
END AS new_name
FROM dirty
  LEFT JOIN clean ON clean.id = dirty.id
ORDER BY dirty.id asc

Example