有没有一种方法可以合并两个表,并使用单个MySQL查询覆盖并乘以结果

时间:2019-08-29 13:18:28

标签: mysql sql

我有三个表,第一个存储大洲,第二个存储默认存在的动物,第三个存储特定大洲和动物的第二个表中的例外。

大陆(最多3个,以简化结果)

| continent_code |
|----------------|
| EU             |
| OC             |
| AN             |

animals_default_presence

| animal_id | animal     | presence |
|-----------|------------|----------|
| 1         | dog        | 1        |
| 2         | kangaroo   | 0        |
| 3         | polar bear | 0        |

continent_animals_presence_exceptions

| continent_code | animal_id | presence |
|----------------|-----------|----------|
| OC             | 2         | 1        |
| AN             | 1         | 0        |
| AN             | 3         | 1        |

结果是其中生活的所有大陆和动物的摘要:

| continent_code | animal_id |
|----------------|-----------|
| EU             | 1         |
| OC             | 1         |
| OC             | 2         |
| AN             | 3         |

我可以通过一个MySQL查询获得这样的结果吗?

2 个答案:

答案 0 :(得分:1)

您可以使用union all。我认为以下就是您所需要的:

select c.continent_code, adp.animal_id
from continent c cross join
     animals_default_presence adp 
where adp.presence = 1 and
      (c.continent_code, adp.animal_id) not in 
            (select cape.continent_code, cape.animal_id
             from continent_animals_presence_exceptions cape
             where cape.presence = 0
            )
union all
select cape.continent_code, cape.animal_id
from continent_animals_presence_exceptions cape
where cape.presence = 1;

Here是db <>小提琴。

答案 1 :(得分:0)

首先,您需要在动物和大洲之间做一个CROSS JOIN,以获取它们的所有可能组合。现在,您可以根据动物和大陆对异常表进行LEFT JOIN

最终,可以使用稍微复杂的WHERE条件来过滤出所需的结果集。我们要么考虑默认存在为1的那些行,要么没有例外;或者,考虑默认存在为0的那些行,但为它们定义一个例外。

SELECT c.continent_code,
       cape.animal_id
FROM   (SELECT c.continent_code,
               a.animal_id,
               a.presence AS default_presence
        FROM   animals_default_presence AS a
               CROSS JOIN continents AS c
              ) AS all_combos
       LEFT JOIN continent_animals_presence_exceptions AS cape
              ON cape.continent_code = default_present_combos.continent_code
                 AND cape.animal_id = default_present_combos.animal_id
WHERE  ( all_combos.default_presence = 1
         AND ( cape.presence = 1
                OR cape.presence IS NULL ) )
        OR ( all_combos.default_presence = 0
             AND cape.presence = 1 ) 

使用UNION ALL的先前版本:

一种方法是利用UNION ALL。在SELECT查询之一中,您可以获取animal和continent_code的所有组合,其中animal的默认存在为 1 。但是,我们将需要使用LEFT JOIN .. WHERE .. IS NULL进行“反加入”,以消除默认动物在特定大陆上的“存在”定义为 0 的例外情况。

在另一个SELECT查询中,我们仅获取默认存在为 0 但在某些大洲中存在为 1 的动物的组合,按照例外中的定义。

SELECT 
  c.continent_code, cape.animal_id 
FROM 
  (SELECT c.continent_code, a.animal_id 
   FROM animals_default_presence AS a 
   CROSS JOIN continents AS c 
   WHERE a.presence = 1) AS default_present_combos 
   LEFT JOIN continent_animals_presence_exceptions AS cape 
          ON cape.continent_code = default_present_combos.continent_code 
             AND cape.animal_id = default_present_combos.animal_id 
             AND cape.presence = 0 
WHERE cape.animal_id IS NULL

UNION ALL 

SELECT 
  cape.continent_code, cape.animal_id 
FROM animals_default_presence AS a 
JOIN continent_animals_presence_exceptions AS cape 
  ON cape.animal_id = a.animal_id 
     AND cape.presence = 1 
WHERE a.presence = 0