摘要:在本教程中,您将学习如何使用 MySQL EXISTS
运算符以及何时使用它来提高查询性能。
MySQL EXISTS
运算符简介
EXISTS
运算符是一个布尔运算符,返回 true 或 false。 EXISTS
运算符通常用于测试子查询返回的行是否存在。
下面说明了EXISTS
运算符的基本语法:
SELECT
select_list
FROM
a_table
WHERE
[NOT] EXISTS(subquery);
Code language: SQL (Structured Query Language) (sql)
如果子查询至少返回一行,则EXISTS
运算符返回 true,否则返回 false。
此外, EXISTS
运算符一旦找到匹配的行,就会立即终止进一步的处理,这有助于提高查询的性能。
NOT
运算符对EXISTS
运算符取反。换句话说,如果子查询没有返回行,则NOT EXISTS
返回 true,否则返回 false。
请注意,您可以在子查询中使用SELECT *
、 SELECT column
、 SELECT a_constant
或任何内容。结果是相同的,因为 MySQL 忽略了SELECT
子句中出现的选择列表。
MySQL EXISTS
运算符示例
让我们举一些使用EXISTS
运算符的示例来了解它的工作原理。
MySQL SELECT EXISTS
示例
考虑示例数据库中的以下customers
和orders
表。

以下语句使用EXISTS
运算符来查找至少拥有一个订单的客户:
SELECT
customerNumber,
customerName
FROM
customers
WHERE
EXISTS(
SELECT
1
FROM
orders
WHERE
orders.customernumber
= customers.customernumber);
Code language: SQL (Structured Query Language) (sql)

在此示例中,对于customers
表中的每一行,查询都会检查orders
表中的customerNumber
。如果customers
表中出现的customerNumber
存在于orders
表中,则子查询将返回第一个匹配行。因此, EXISTS
运算符返回 true 并停止检查orders
表。否则,子查询不返回任何行,并且EXISTS
运算符返回 false。
以下示例使用NOT EXISTS
运算符查找没有任何订单的客户:
SELECT
customerNumber,
customerName
FROM
customers
WHERE
NOT EXISTS(
SELECT
1
FROM
orders
WHERE
orders.customernumber = customers.customernumber
);
Code language: SQL (Structured Query Language) (sql)

MySQL UPDATE EXISTS
示例
假设您必须更新在旧金山办公室工作的员工的电话分机。
以下语句查找在San Franciso
办公室工作的员工:
SELECT
employeenumber,
firstname,
lastname,
extension
FROM
employees
WHERE
EXISTS(
SELECT
1
FROM
offices
WHERE
city = 'San Francisco' AND
offices.officeCode = employees.officeCode);
Code language: SQL (Structured Query Language) (sql)

此示例将号码 1 添加到在旧金山办公室工作的员工的电话分机号:
UPDATE employees
SET
extension = CONCAT(extension, '1')
WHERE
EXISTS(
SELECT
1
FROM
offices
WHERE
city = 'San Francisco'
AND offices.officeCode = employees.officeCode);
Code language: SQL (Structured Query Language) (sql)
怎么运行的。
MySQL INSERT EXISTS
示例
假设您要将没有任何销售订单的客户存档在单独的表中。为此,您可以使用以下步骤:
首先,通过复制客户表的结构来创建一个用于归档customers
的新表:
CREATE TABLE customers_archive
LIKE customers;
Code language: SQL (Structured Query Language) (sql)
其次,使用以下INSERT
语句将没有任何销售订单的客户插入到customers_archive
表中。
INSERT INTO customers_archive
SELECT *
FROM customers
WHERE NOT EXISTS(
SELECT 1
FROM
orders
WHERE
orders.customernumber = customers.customernumber
);
Code language: SQL (Structured Query Language) (sql)
第三,从customers_archive
表中查询数据来验证插入操作。
SELECT * FROM customers_archive;
Code language: SQL (Structured Query Language) (sql)

MySQL DELETE EXISTS
示例
归档客户数据的最后一项任务是从customers
表中删除customers_archive
表中存在的客户。
为此,您可以在DELETE
语句的WHERE
子句中使用EXISTS
运算符,如下所示:
DELETE FROM customers
WHERE EXISTS(
SELECT
1
FROM
customers_archive a
WHERE
a.customernumber = customers.customerNumber);
Code language: SQL (Structured Query Language) (sql)
MySQL EXISTS
运算符与IN
运算符
要查找至少下过一份订单的客户,您可以使用IN
运算符,如以下查询所示:
SELECT
customerNumber,
customerName
FROM
customers
WHERE
customerNumber IN (
SELECT
customerNumber
FROM
orders);
Code language: SQL (Structured Query Language) (sql)
让我们通过EXPLAIN
语句来比较使用IN
运算符的查询和使用EXISTS
运算符的查询。
EXPLAIN SELECT
customerNumber,
customerName
FROM
customers
WHERE
EXISTS(
SELECT
1
FROM
orders
WHERE
orders.customernumber = customers.customernumber);
Code language: SQL (Structured Query Language) (sql)

现在,检查使用IN
运算符的查询的性能。
SELECT
customerNumber, customerName
FROM
customers
WHERE
customerNumber IN (SELECT
customerNumber
FROM
orders);
Code language: SQL (Structured Query Language) (sql)

使用EXISTS
运算符的查询比使用IN
运算符的查询快得多。
原因是EXISTS
运算符基于“至少找到”原则工作。当找到匹配的行时, EXISTS
停止扫描表。
另一方面,当IN
运算符与子查询组合时,MySQL 必须先处理子查询,然后使用子查询的结果来处理整个查询。
一般的经验法则是,如果子查询包含大量数据,则EXISTS
运算符可提供更好的性能。
但是,如果子查询返回的结果集非常小,则使用IN
运算符的查询执行速度会更快。
例如,以下语句使用IN
运算符选择在旧金山办公室工作的所有员工。
SELECT
employeenumber,
firstname,
lastname
FROM
employees
WHERE
officeCode IN (SELECT
officeCode
FROM
offices
WHERE
offices.city = 'San Francisco');
Code language: SQL (Structured Query Language) (sql)
让我们检查一下查询的性能。

它比我们在第一个示例中提到的使用EXISTS
运算符的查询要快一点。请参阅下面使用EXIST
运算符的查询的性能:

在本教程中,您学习了如何使用 MySQL EXISTS
运算符来测试子查询返回的行是否存在。