PHP 入门教程
MySQL 高级查询
本教程共 65 篇 · 第 57 篇 · 更新于 2026-07-24 · 约 8 分钟阅读
PHPPHP8MySQLJOINGROUP BY聚合函数子查询HAVING
57. MySQL 高级查询
本节目标:掌握多表联查、分组聚合和子查询,能够处理复杂的数据统计需求。
单表查询能解决基础需求,但真实业务中数据通常分散在多张表中。本节学习将多张表的数据整合到一起的高级查询技术。
1. JOIN 多表联查
内连接(INNER JOIN)
只返回两表匹配的记录:
SELECT u.username, o.total_price
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
左连接(LEFT JOIN)
返回左表所有记录,右表不匹配则填 NULL:
-- 查询所有用户及其订单(没有订单的用户也显示)
SELECT u.username, o.total_price
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
右连接(RIGHT JOIN)
返回右表所有记录,左表不匹配则填 NULL:
SELECT u.username, o.total_price
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
Tip实际开发中
LEFT JOIN最常用。建议将主要数据表放左边,关联表放右边。
2. GROUP BY 分组聚合
按指定字段分组后,对每组进行统计计算。
-- 统计每个用户的订单数量
SELECT
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_price) AS total_amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username;
常用聚合函数
| 函数 | 作用 |
|---|---|
COUNT(*) | 统计行数 |
SUM(字段) | 求和 |
AVG(字段) | 平均值 |
MAX(字段) | 最大值 |
MIN(字段) | 最小值 |
3. HAVING 过滤分组
WHERE 在分组前过滤行,HAVING 在分组后过滤组。
-- 找出订单总金额超过 1000 的用户
SELECT
u.username,
SUM(o.total_price) AS total
FROM users u
JOIN orders o ON u.id = o.user_id
GROUP BY u.id
HAVING total > 1000;
Note
HAVING可以使用聚合函数的别名,WHERE不能。
4. 子查询
子查询是嵌套在另一个查询中的查询,可以作为条件或临时表使用。
作为条件
-- 查询有订单的用户
SELECT * FROM users
WHERE id IN (SELECT DISTINCT user_id FROM orders);
作为临时表
-- 查询订单数前 3 的用户
SELECT username, order_count
FROM (
SELECT u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id
) AS temp
ORDER BY order_count DESC
LIMIT 3;
5. PHP 高级查询示例
<?php
$pdo = new PDO('mysql:host=localhost;dbname=my_shop;charset=utf8mb4', 'root', '123456');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 用户订单统计
$stmt = $pdo->query("
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
IFNULL(SUM(o.total_price), 0) AS total_amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id
HAVING total_amount > 0
ORDER BY total_amount DESC
LIMIT 10
");
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
echo "{$row['username']}: {$row['order_count']} 单,共 {$row['total_amount']} 元<br>";
}
Tip
IFNULL(SUM(...), 0)用于处理没有订单的用户,避免合计为 NULL。
小结
JOIN 整合多表数据,GROUP BY + 聚合函数做统计,HAVING 过滤统计结果,子查询处理复杂条件。这四项技术组合使用,能应对绝大多数业务查询需求。
来源:参考了 runoob「PHP MySQL 高级教程」、PHP 官方文档,改写后所得。