← PHP查询MySQL数据:SELECT语句 PHP发送邮件:mail()函数 →

PHP数据排序:ORDER BY子句

原创 2026-05-21 PHP 已有人查阅

从数据库捞数据出来,默认顺序是按插入顺序排列的。但实际业务中,你得按价格排序、按时间排序、按销量排序。这时候ORDER BY就派上用场了。

排序规则:

  • ASC — 升序,从小到大,从A到Z。不写的话默认就是ASC

  • DESC — 降序,从大到小,从Z到A

一个真实场景: 电商后台看订单,运营肯定想先看新的订单在最上面,那就ORDER BY created_at DESC。要是看销量排行榜,那就是ORDER BY sales_count DESC。

ORDER BY语法

SELECT 字段名 FROM 表名 ORDER BY 排序字段 ASC|DESC;

支持多字段排序:

SELECT * FROM products ORDER BY category ASC, price DESC;

先按分类升序排,同一个分类里面再按价格降序排。

示例数据表

本文用到的表:employees

id name salary
1 赵大柱 30000
2 钱小毛 40000
3 孙漂亮 35000

升序排列(ASC)

默认就是升序,所以ORDER BY name和ORDER BY name ASC结果一样。

<?php
$host = 'localhost:3306';
$user = 'root';
$pass = '123456';
$dbname = 'company_db';

$conn = mysqli_connect($host, $user, $pass, $dbname);

if (!$conn) {
    die('连不上数据库:' . mysqli_connect_error());
}

$sql = 'SELECT id, name, salary FROM employees ORDER BY name';
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
    while ($row = mysqli_fetch_assoc($result)) {
        echo "工号:" . $row['id'] . "<br>";
        echo "姓名:" . $row['name'] . "<br>";
        echo "工资:" . $row['salary'] . "<br>";
        echo "-------------------<br>";
    }
} else {
    echo "没有查到数据";
}

mysqli_close($conn);
?>

排序前(原始数据):

id name salary
1 赵大柱 30000
2 钱小毛 40000
3 孙漂亮 35000

排序后(ORDER BY name升序):

id name salary
3 孙漂亮 35000
2 钱小毛 40000
1 赵大柱 30000

按拼音字母顺序排:孙(sun)、钱(qian)、赵(zhao)

个人经验: 中文排序在MySQL里是按拼音来的,这点和英文不一样。如果表字段用的是utf8_general_ci,中文排序基本没问题。但如果你想要按笔画排序,那得单独处理。

降序排列(DESC)

工资从高到低排,老板看工资表的时候最常用。

<?php
$host = 'localhost:3306';
$user = 'root';
$pass = '123456';
$dbname = 'company_db';

$conn = mysqli_connect($host, $user, $pass, $dbname);

if (!$conn) {
    die('连不上数据库:' . mysqli_connect_error());
}

$sql = 'SELECT id, name, salary FROM employees ORDER BY salary DESC';
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
    while ($row = mysqli_fetch_assoc($result)) {
        echo "工号:" . $row['id'] . "<br>";
        echo "姓名:" . $row['name'] . "<br>";
        echo "工资:" . $row['salary'] . "<br>";
        echo "-------------------<br>";
    }
} else {
    echo "没有查到数据";
}

mysqli_close($conn);
?>

排序前:

id name salary
1 赵大柱 30000
2 钱小毛 40000
3 孙漂亮 35000

排序后(ORDER BY salary DESC):

id name salary
2 钱小毛 40000
3 孙漂亮 35000
1 赵大柱 30000

说一下: 30000是较低的,所以排到了之后。这就是降序的效果。

MySQLi面向对象方式排序

<?php
$mysqli = new mysqli("localhost", "root", "123456", "company_db");

if ($mysqli->connect_error) {
    die("连接失败:" . $mysqli->connect_error);
}

$sql = "SELECT id, name, salary FROM employees ORDER BY salary DESC";
$result = $mysqli->query($sql);

if ($result->num_rows > 0) {
    echo "<table border='1'>";
    echo "<tr><th>工号</th><th>姓名</th><th>工资</th></tr>";
    while ($row = $result->fetch_assoc()) {
        echo "<tr>";
        echo "<td>" . $row['id'] . "</td>";
        echo "<td>" . $row['name'] . "</td>";
        echo "<td>" . $row['salary'] . "</td>";
        echo "</tr>";
    }
    echo "</table>";
} else {
    echo "没有数据";
}

$mysqli->close();
?>

原始表数据:

id name salary
1 赵大柱 30000
2 钱小毛 40000
3 孙漂亮 35000

输出表格:

工号 姓名 工资
2 钱小毛 40000
3 孙漂亮 35000
1 赵大柱 30000

PDO方式排序

PDO的预处理配合ORDER BY有个细节需要注意:ORDER BY后面的字段名不能用占位符绑定。这是SQL语法的限制,字段名和表名不能参数化。

<?php
try {
    $pdo = new PDO("mysql:host=localhost;dbname=company_db", "root", "123456");
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    // 排序字段和方向不能绑定参数,只能直接拼接
    // 但如果你是从用户输入获取排序字段,必须做白名单校验
    $sort_field = 'salary';     // 来自用户输入时要校验
    $sort_order = 'DESC';       // 来自用户输入时要校验
    
    $sql = "SELECT id, name, salary FROM employees ORDER BY $sort_field $sort_order";
    $stmt = $pdo->prepare($sql);
    $stmt->execute();
    
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    echo "<table border='1'>";
    echo "<tr><th>工号</th><th>姓名</th><th>工资</th></table>";
    
    foreach ($results as $row) {
        echo "<td>";
        echo "<td>" . $row['id'] . "</td>";
        echo "<td>" . $row['name'] . "</td>";
        echo "<td>" . $row['salary'] . "</td>";
        echo "</tr>";
    }
    echo "</table>";
    
} catch (PDOException $e) {
    echo "查询失败:" . $e->getMessage();
}

$pdo = null;
?>

个人见解: PDO确实好用,但ORDER BY这里是个例外。因为字段名不能做参数绑定,所以如果排序字段来自前端传参(比如用户点击表头排序),必须在后端做白名单校验,不然会有SQL注入风险。

安全写法示例:

// 允许排序的字段白名单
$allowed_sort_fields = ['id', 'name', 'salary', 'created_at'];
$sort_field = $_GET['sort'] ?? 'id';

if (!in_array($sort_field, $allowed_sort_fields)) {
    $sort_field = 'id';  // 非法字段就回退到默认
}

$allowed_orders = ['ASC', 'DESC'];
$sort_order = strtoupper($_GET['order'] ?? 'ASC');

if (!in_array($sort_order, $allowed_orders)) {
    $sort_order = 'ASC';
}

$sql = "SELECT * FROM employees ORDER BY $sort_field $sort_order";

多字段排序

实际业务经常需要先按A排,再按B排。

代码号学习编程示例:

<?php
// 先按部门升序,同一部门内按工资降序
$sql = "SELECT id, name, department, salary 
        FROM employees 
        ORDER BY department ASC, salary DESC";

$result = mysqli_query($conn, $sql);

数据示例:

id name department salary
1 张三 技术部 15000
2 李四 技术部 12000
3 王五 市场部 13000
4 赵六 市场部 11000

排序后:

id name department salary
1 张三 技术部 15000
2 李四 技术部 12000
3 王五 市场部 13000
4 赵六 市场部 11000

技术部在前(A在M前面),技术部内部工资高的在前;市场部在后,内部也是工资高的在前。

结合WHERE条件排序

<?php
// 只查工资大于10000的员工,按工资从高到低排
$sql = "SELECT id, name, salary 
        FROM employees 
        WHERE salary > 10000 
        ORDER BY salary DESC";

执行顺序是:WHERE先过滤 → 再排序 → 之后返回结果。

HTML表格输出排序结果

后台管理页面经常需要把排序后的数据用表格展示。

<?php
$conn = mysqli_connect("localhost", "root", "123456", "company_db");

if (!$conn) {
    die("连接失败:" . mysqli_connect_error());
}

$sql = "SELECT id, name, salary FROM employees ORDER BY salary DESC";

if ($result = mysqli_query($conn, $sql)) {
    if (mysqli_num_rows($result) > 0) {
        echo "<table border='1' cellpadding='8'>";
        echo "<tr><th>工号</th><th>姓名</th><th>工资(元)</th></table>";
        
        while ($row = mysqli_fetch_array($result)) {
            echo "<tr>";
            echo "<td>" . $row['id'] . "</td>";
            echo "<td>" . $row['name'] . "</td>";
            echo "<td>" . number_format($row['salary']) . "</td>";
            echo "</tr>";
        }
        echo "</table>";
        mysqli_free_result($result);
    } else {
        echo "没有找到记录";
    }
} else {
    echo "查询执行失败:" . mysqli_error($conn);
}

mysqli_close($conn);
?>

number_format()的作用: 把30000显示成30,000,老板看着舒服。

本节课程知识要点

  1. 默认排序是ASC — ORDER BY字段名 等同于 ORDER BY字段名 ASC

  2. 多字段排序有优先级 — 写在前面的字段先排序,前面的字段值相同才用到后面的字段

  3. 排序字段不能参数化 — PDO的prepare不能绑定字段名,必须用白名单校验

  4. 大表排序要建索引 — 经常用来排序的字段(比如created_at、price),记得建索引。没索引的话数据量大了会慢得很明显

  5. NULL值的排序位置 — MySQL里NULL在升序时排在最前面,降序时排在之后面。这点和有些数据库不一样,需要注意

-- 把NULL值放到之后(升序时)
SELECT * FROM products ORDER BY IFNULL(price, 999999) ASC;

-- 或者用COALESCE
SELECT * FROM products ORDER BY COALESCE(price, 999999) ASC;

常见问题

Q:ORDER BY和GROUP BY一起用时怎么写?
A:GROUP BY在前,ORDER BY在后。先分组再排序。

SELECT department, AVG(salary) as avg_salary 
FROM employees 
GROUP BY department 
ORDER BY avg_salary DESC;

Q:中文排序不按拼音怎么办?
A:检查表的排序规则,改成utf8_general_ci或者gbk_chinese_ci。

-- 临时指定排序规则
SELECT name FROM employees ORDER BY name COLLATE utf8_general_ci;
← PHP查询MySQL数据:SELECT语句 PHP发送邮件:mail()函数 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号