使用 Set 运算符查询以显示特定列

Query to display specific columns using a Set operator

我正在尝试使用 Set 运算符来显示没有城市名称(Table A col.)的国家名称(Table B col.)和没有国家名称(A)的城市名称(B) ).我还尝试使用 LEFT JOINS 编写此查询,如下所示,我包括 Table C(Regions) 因为我不确定是否在 LEFT JOIN 中使用该主键。

Table A(国家/地区):

Column_name   |   Column_id
              |
COUNTRY_ID    |     1
COUNTRY_NAME  |     2
REGION_ID     |     3

Table B(位置):

Column_name   |   Column_id
              |
LOCATION_ID   |     1
   CITY       |     4
COUNTRY_ID    |     6

Table C(地区):

Column_name   |   Column_id
              |
 REGION_ID    |     1

我试过以下方法:

SELECT c.country_name, l.city
FROM Countries c
LEFT JOIN Locations l ON c.country_id = l.country_id

UNION

SELECT c2.country_name, l2.city
FROM Countries c2
LEFT JOIN Locations l2 ON c2.country_id = l2.country_id;

上面的SQL语句返回了所有Table A值,Table A值不包含Table B值(没有城市的国家) .

我也试过下面这个语句,得到了完全相同的结果:

SELECT c.country_name, l.city
FROM Countries c
LEFT JOIN Locations l ON c.country_id = l.country_id
LEFT JOIN Regions r ON r.region_id = c.region_id;

它缺少的一件事是 Table 在 Table B 中找不到值(在城市中找不到国家。)

有很多选项可以获得您想要的结果。一种方法是使用 LEFT JOIN 获取没有城市的国家和 RIGHT JOIN 获取没有国家的城市:

SELECT c.country_name, l.city
FROM countries c
LEFT JOIN locations l ON c.country_id = l.country_id
WHERE l.city IS NULL
UNION ALL
SELECT c.country_name, l.city
FROM countries c
RIGHT JOIN locations l ON c.country_id = l.country_id
WHERE c.country_name IS NULL;

另一种可能是使用两个LEFT JOIN,但是从相反的table开始,像这样:

SELECT c.country_name, l.city
FROM countries c
LEFT JOIN locations l ON c.country_id = l.country_id
WHERE l.city IS NULL
UNION ALL
SELECT c.country_name, l.city
FROM locations l
LEFT JOIN countries c ON c.country_id = l.country_id
WHERE c.country_name IS NULL;

如果您根本不喜欢使用 JOIN,您可以使用 NOT IN:

SELECT c.country_name, NULL city
FROM countries c
WHERE country_id NOT IN (SELECT country_id FROM locations)
UNION ALL
SELECT NULL country_name, l.city
FROM locations l
WHERE country_id NOT IN (SELECT country_id FROM countries);

或者,如果您更喜欢 NOT EXISTS,这也行得通:

SELECT c.country_name, NULL city
FROM countries c
WHERE NOT EXISTS (SELECT 1 FROM locations WHERE country_id = c.country_id)
UNION ALL
SELECT NULL country_name, l.city
FROM locations l
WHERE NOT EXISTS (SELECT 1 FROM countries WHERE country_id = l.country_id);

我创建了一个示例,显示所有这些查询将产生相同的结果:db<>fiddle

ORDER BY c.country_nameORDER BY l.city 添加到查询中,以防您希望结果集按它们排序。

最后但重要的注意事项:如您所见,我使用 UNION ALL 而不是 UNION 因为我看不出在您的用例中使用 UNION 的原因. UNION ALL 快得多,所以我建议使用它,除非有真正令人信服的理由不使用它。 UNION 的唯一优点是它不会显示重复的行,但我认为它们在您的情况下不太可能,因此不应该是必需的。

使用集合运算符查找没有城市的国家/地区的最简单示例是:

select country_id from countries
minus
select country_id from locations
COUNTRY_ID
----------
         1
         4

因为需要国名,所以查一下就可以了:

select country_name from countries
minus
select c.country_name from locations l
       join countries c on c.country_id = l.country_id;
COUNTRY_NAME
-----------------
England
Italy

没有国家(或国家代码无效)的城市作为左连接和过滤器更简单:

select l.city, l.country_id
from   locations l
       left join countries c on c.country_id = l.country_id
where  c.country_id is null
CITY             
-----------------
Berlin           
Tokyo            

如果确实需要使用集合运算符来执行此操作,您将(从概念上)查找其 country_id 在(位置国家/地区减去城市国家/地区)集合中的城市:

select l.location_id, l.city, l.country_id
from   locations l
where  l.country_id in
       ( select country_id from locations
         minus
         select country_id from countries )

但是,这不会为您提供 country_id 为空的位置。