MySQL 子查询
简介:在本教程中,我们将向您展示如何使用MySQL子查询编写复杂查询并解释相关子查询概念。
一个MySQL子查询是嵌套在另一个查询内,如查询
SELECT
,INSERT
,UPDATE
,DELETE
。此外,MySQL子查询可以嵌套在另一个子查询中。
MySQL子查询称为内部查询,而包含子查询的查询称为外部查询。子查询可以在任何使用表达式的地方使用,并且必须在括号中关闭。
以下查询返回在美国办事处工作的员工。
SELECT lastName, firstName FROM employees WHERE officeCode IN (SELECT officeCode FROM offices WHERE country = 'USA');在这个例子中:
- 子查询返回位于美国的办事处的所有办公代码。
- 外部查询选择在办公室代码位于子查询返回的结果集中的办公室中工作的员工的姓氏和名字。
MySQL子查询在WHERE子句中
我们将使用示例数据库中的payments
表进行演示。
+----------------+ | payments | +----------------+ | customerNumber | | checkNumber | | paymentDate | | amount | +----------------+ 4 rows in set (0.02 sec)
MySQL子查询带有比较运算符
您可以使用比较运算符(例如,=,>,<等等)将子查询返回的单个值与WHERE
子句中的表达式进行比较。
例如,以下查询返回具有最高付款金额的客户。
SELECT customerNumber, checkNumber, amount FROM payments WHERE amount = (SELECT MAX(amount) FROM payments);运行结果:
+----------------+-------------+-----------+ | customerNumber | checkNumber | amount | +----------------+-------------+-----------+ | 141 | JE105477 | 120166.58 | +----------------+-------------+-----------+ 1 row in set (0.02 sec)除了等于运算符,您还可以使用其他比较运算符,例如大于(
>
),小于(<
)等。
例如,您可以使用子查询查找付款大于平均付款的客户。首先,在子查询使用AVG
聚合函数计算平均付款。然后,在外部查询中,查询大于子查询返回的平均付款的付款。
SELECT customerNumber, checkNumber, amount FROM payments WHERE amount > (SELECT AVG(amount) FROM payments);运行结果:
+----------------+-------------+-----------+ | customerNumber | checkNumber | amount | +----------------+-------------+-----------+ | 112 | HQ55022 | 32641.98 | | 112 | ND748579 | 33347.88 | | 114 | GG31455 | 45864.03 | | 114 | MA765515 | 82261.22 | | 114 | NR27552 | 44894.74 | | 119 | LN373447 | 47924.19 | ...
MySQL子查询带有IN和NOT IN运算符
如果子查询返回多个值,则可以在WHERE
子句中使用其他运算符,例如IN
或NOT IN
运算符。
请参阅以下内容customers
和orders
表格:
+------------------------+ | customers | +------------------------+ | customerNumber | | customerName | | contactLastName | | contactFirstName | | phone | | addressLine1 | | addressLine2 | | city | | state | | postalCode | | country | | salesRepEmployeeNumber | | creditLimit | +------------------------+ 13 rows in set (0.00 sec) +----------------+ | orders | +----------------+ | orderNumber | | orderDate | | requiredDate | | shippedDate | | status | | comments | | customerNumber | +----------------+ 7 rows in set (0.00 sec)例如,您可以使用带有
NOT IN
运算符的子查询来查找没有订单的客户,如下所示:
SELECT customerName FROM customers WHERE customerNumber NOT IN (SELECT DISTINCT customerNumber FROM orders);运行结果:
+--------------------------------+ | customerName | +--------------------------------+ | Havel & Zbyszek Co | | American Souvenirs Inc | | Porto Imports Co. | | Asian Shopping Network, Co | | Natrlich Autos | | ANG Resellers | | Messner Shopping Network | ...
MySQL子查询中的FROM子句
在FROM
子句中使用子查询时,从子查询返回的结果集将用作临时表。此表称为派生表或实现子查询。
以下子查询查找销售订单中的最大,最小和平均项数:
SELECT MAX(items), MIN(items), FLOOR(AVG(items)) FROM (SELECT orderNumber, COUNT(orderNumber) AS items FROM orderdetails GROUP BY orderNumber) AS lineitems;运行结果:
+------------+------------+-------------------+ | MAX(items) | MIN(items) | FLOOR(AVG(items)) | +------------+------------+-------------------+ | 18 | 1 | 9 | +------------+------------+-------------------+ 1 row in set (0.00 sec)
注意:
FLOOR()
函数用于从项目的平均值中删除小数位。
MySQL相关子查询
在前面的示例中,您注意到子查询是独立的。这意味着您可以将子查询作为独立查询执行,例如:SELECT orderNumber, COUNT(orderNumber) AS items FROM orderdetails GROUP BY orderNumber;与独立子查询不同,相关子查询是使用外部查询中的数据的子查询。换句话说,相关子查询取决于外部查询。对外部查询中的每一行评估一次相关子查询。 在以下查询中,我们选择购买价格高于每个 产品系列中所有产品的平均购买价格的产品。
SELECT productname, buyprice FROM products p1 WHERE buyprice > (SELECT AVG(buyprice) FROM products WHERE productline = p1.productline)运行结果:
+-----------------------------------------+----------+ | productname | buyprice | +-----------------------------------------+----------+ | 1952 Alpine Renault 1300 | 98.58 | | 1996 Moto Guzzi 1100i | 68.99 | | 2003 Harley-Davidson Eagle Drag Bike | 91.02 | | 1972 Alfa Romeo GTA | 85.68 | | 1962 LanciaA Delta 16V | 103.42 | | 1968 Ford Mustang | 95.34 | ...内部查询针对每个产品系列执行,因为每行都更改了产品系列。因此,平均购买价格也会发生变化。外部查询仅筛选购买价格高于子查询中每个产品系列的平均购买价格的产品。
MySQL子查询带有EXISTS和NOT EXISTS
当子查询与EXISTS
or NOT EXISTS
运算符一起使用时,子查询返回布尔值TRUE
or FALSE
。以下查询说明了与EXISTS
运算符一起使用的子查询:
SELECT * FROM table_name WHERE EXISTS( subquery );在上面的查询中,如果子查询返回任何行,则
EXISTS subquery
返回TRUE
,否则返回FALSE
。
EXISTS
和NOT EXISTS
经常在用于相关子查询。
我们来看看示例数据库中的orders和orderDetails表:
+----------------+ | orders | +----------------+ | orderNumber | | orderDate | | requiredDate | | shippedDate | | status | | comments | | customerNumber | +----------------+ 7 rows in set (0.00 sec) +-----------------+ | orderdetails | +-----------------+ | orderNumber | | productCode | | quantityOrdered | | priceEach | | orderLineNumber | +-----------------+ 5 rows in set (0.01 sec)以下查询选择总值大于60K的销售订单。
SELECT orderNumber, SUM(priceEach * quantityOrdered) total FROM orderdetails INNER JOIN orders USING (orderNumber) GROUP BY orderNumber HAVING SUM(priceEach * quantityOrdered) > 60000;运行结果:
+-------------+----------+ | orderNumber | total | +-------------+----------+ | 10165 | 67392.85 | | 10287 | 61402.00 | | 10310 | 61234.67 | +-------------+----------+ 3 rows in set (0.01 sec)它返回3行,这意味着有3个销售订单的总值大于60K。 可以使用上面的查询作为相关子查询来查找通过使用
EXISTS
运算符放置至少一个总值大于60K的销售订单的客户:
SELECT customerNumber, customerName FROM customers WHERE EXISTS( SELECT orderNumber, SUM(priceEach * quantityOrdered) FROM orderdetails INNER JOIN orders USING (orderNumber) WHERE customerNumber = customers.customerNumber GROUP BY orderNumber HAVING SUM(priceEach * quantityOrdered) > 60000);运行结果:
+----------------+-------------------------+ | customerNumber | customerName | +----------------+-------------------------+ | 148 | Dragon Souveniers, Ltd. | | 259 | Toms Spezialitten, Ltd | | 298 | Vida Sport, Ltd | +----------------+-------------------------+ 3 rows in set (0.01 sec)在本教程中,我们向您展示了如何使用MySQL子查询和相关子查询来构造更复杂的查询。