首页 / PHP 入门教程 / MySQL 高级查询

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 官方文档,改写后所得。