在数据库操作中,经常需要从多个表中提取数据,并将这些数据进行合并、比较或排除。SQL提供了多种操作符来实现这些需求,包括UNION、INTERSECT和EXCEPT。这些操作符可以帮助以灵活的方式查询数据,但同时也需要注意它们的使用规则和优化技巧。
UNION操作符用于合并两个或多个SELECT语句的结果集,返回唯一的结果集。如果使用UNION ALL,则会返回所有重复的结果。UNION操作符非常适合用于将两个独立查询的结果合并为一个排序的结果集。例如,如果有两个表:Vendor和Customer,想要一个包含这两个表中所有名字的合并列表,可以使用以下SQL语句:
SELECT 'Vendor', V.Name FROM Vendor V
UNION
SELECT 'Customer', C.Name FROM Customer C
ORDER BY Name;
注意,ORDER BY子句应用于合并后的结果集。
INTERSECT操作符用于返回两个查询共有的行,即返回左右查询结果中都存在的行。当想要找到两个查询共有的结果时,这个操作符非常有用。例如,如果想要找到既是供应商又是客户的供应商,可以使用以下SQL语句:
SELECT V.Name FROM Vendor V
INTERSECT
SELECT C.Name FROM Customer C
ORDER BY Name;
同样,也可以使用INNERJOIN来实现相同的查询:
SELECT DISTINCT V.Name FROM Vendor V
INNER JOIN Customer C ON V.Name = C.Name
ORDER BY V.Name;
会发现,在SQL中通常有多种方法来解决同一个问题。
EXCEPT操作符用于返回仅存在于左侧查询中的行,即返回左侧查询中有而右侧查询中没有的唯一行。当想要找到存在于一个集合中但不在另一个集合中的行时,这个操作符非常有用。例如,如果想要创建一个不是客户的供应商列表,可以编写以下SQL语句:
SELECT V.Name FROM Vendor V
EXCEPT
SELECT C.Name FROM Customer C
ORDER BY Name;
与INTERSECT一样,EXCEPT也有一个等价的SQL语句,可以使用OUTERJOIN来构建它的等价语句:
SELECT DISTINCT V.Name FROM Vendor V
LEFT OUTER JOIN Customer C ON V.Name = C.Name
WHERE C.Name IS NULL
ORDER BY V.Name;
可以使用这些操作符构建复杂的查询。事实上,没有什么可以阻止将一个或多个这些操作符组合成一个超级查询。当这样做时,确保使用括号“()”来控制哪些操作符首先被评估。
SELECT A FROM TA
INTERSECT
SELECT B FROM TB
EXCEPT
SELECT C FROM TC
UNION
SELECT D FROM TD;
如果没有括号,评估的顺序是:先评估INTERSECT和EXCEPT,然后评估UNION。能否记住这个顺序?建议是使用括号并使其清晰。虽然复杂很酷,但当误读自己的代码时,可能会在将来遭受挫折——相信。
在这三个查询中,UNION操作符是不可替代的。没有其他方法可以在不使用UNION的情况下将两个查询的结果合并为一个单一的结果。另一方面,正如之前看到的,EXCEPT和INTERSECT的结果可以使用OUTER和INNER JOINS来复制。实际上,会发现JOIN版本的查询比EXCEPT和INTERSECT运行得更高效,并且更灵活,因为可以从左侧表中包含右侧表中没有的字段。
SELECT V.Name, V.Address FROM Vendor V
EXCEPT
SELECT C.Name FROM Customer C
ORDER BY Name;
这是无效的,因为两个查询中的列数不匹配,而...
SELECT DISTINCT V.Name, V.Address FROM Vendor V
LEFT OUTER JOIN Customer C ON V.Name = C.Name
WHERE C.Name IS NULL
ORDER BY V.Name;