W3docs

Использование конструкции MySQL ORDER BY в PHP

Узнайте, как использовать ORDER BY в MySQL из PHP: синтаксис, сортировка по нескольким столбцам, значения NULL и безопасная сортировка по выбору пользователя.

Запрос SELECT без ORDER BY возвращает строки в порядке, который MySQL не гарантирует — он может меняться между запусками, версиями сервера или после обслуживания таблицы. Конструкция ORDER BY делает этот порядок явным, сортируя результирующий набор по одному или нескольким столбцам. На этой странице показано, как использовать её в PHP: синтаксис, восходящая и нисходящая сортировка, сортировка по нескольким столбцам, место значений NULL и безопасная сортировка по столбцу, выбранному пользователем, без риска SQL-инъекции.

Если вы только начинаете выполнять запросы из PHP, сначала ознакомьтесь с подключением к MySQL и выборкой данных.

Синтаксис

SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC | DESC], column2 [ASC | DESC], ...;
  • ASC сортирует по возрастанию (A→Z, 0→9, от старых к новым) и является значением по умолчаниюORDER BY age и ORDER BY age ASC идентичны.
  • DESC сортирует по убыванию (Z→A, 9→0, от новых к старым).
  • Направление применяется к каждому столбцу отдельно, поэтому их можно комбинировать: ORDER BY country ASC, age DESC.

ORDER BY выполняется после фильтрации WHERE и группировки GROUP BY, поэтому сортирует только те строки, которые прошли эти шаги. Это последняя конструкция перед LIMIT.

Базовый пример

Следующий запрос выбирает имена и возраст и сортирует клиентов от старшего к младшему:

<?php

$conn = new mysqli("localhost", "username", "password", "database");
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

$sql = "SELECT name, age FROM customers ORDER BY age DESC";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        echo "Name: " . $row["name"] . " - Age: " . $row["age"] . "<br>";
    }
} else {
    echo "0 results";
}

$conn->close();
?>

Мы подключаемся с помощью класса mysqli, выбираем name и age из таблицы customers и используем ORDER BY age DESC, чтобы наибольший возраст шёл первым. Замените DESC на ASC (или уберите его), чтобы первыми шли самые молодые.

Сортировка по нескольким столбцам

Когда несколько строк имеют одинаковое значение в первом столбце сортировки, следующий столбец разрешает равенство. Порядок столбцов в конструкции определяет приоритет:

SELECT name, country, age
FROM customers
ORDER BY country ASC, age DESC;

Это группирует клиентов по country в алфавитном порядке, а внутри каждой страны выводит сначала самых старших. Для данных ниже:

namecountryage
AnnaCanada41
BenCanada29
CarlaMexico50

ORDER BY country ASC, age DESC вернёт Anna, Ben, Carla — Canada перед Mexico, а Anna перед Ben, потому что 41 > 29.

Как сортируются значения NULL

В MySQL NULL считается меньше любого ненулевого значения:

  • При ASC строки, где столбец сортировки равен NULL, появляются первыми.
  • При DESC они появляются последними.

Чтобы принудительно поместить NULL-значения в конец независимо от направления, сначала выполните сортировку по признаку отсутствия значения:

SELECT name, last_login
FROM users
ORDER BY last_login IS NULL, last_login DESC;

last_login IS NULL возвращает 0 для реальных дат и 1 для null, поэтому ненулевые строки (0) идут перед нулевыми (1).

Безопасная сортировка по столбцу, выбранному во время выполнения

Распространённая задача — позволить пользователю выбирать столбец сортировки, например ?sort=name. Нельзя привязать имя столбца или ключевое слово ASC/DESC через плейсхолдер подготовленного запроса — плейсхолдеры работают только для значений. Конкатенация сырого запроса в SQL создаёт уязвимость SQL-инъекции. Вместо этого проверяйте входные данные по списку разрешённых значений:

<?php
// Map user input to known-good column names.
$allowedColumns = [
    "name" => "name",
    "age"  => "age",
    "date" => "created_at",
];

$sortKey   = $_GET["sort"] ?? "name";
$column    = $allowedColumns[$sortKey] ?? "name";          // fallback if unknown
$direction = (($_GET["dir"] ?? "asc") === "desc") ? "DESC" : "ASC";

// $column and $direction can now only be values we put in the code.
$sql = "SELECT name, age FROM customers ORDER BY $column $direction";
$result = $conn->query($sql);
?>

Пользователь передаёт только ключ массива; настоящее имя столбца и направление берутся из констант в вашем коде, поэтому непроверенные данные никогда не попадают в строку запроса. Это единственный случай, когда построение SQL через конкатенацию допустимо — потому что каждое возможное значение написано вами.

Примечание: ORDER BY сам по себе никогда не принимает пользовательские значения, поэтому не использует привязанные параметры. Любые значения WHERE в том же запросе всё равно должны быть привязаны через подготовленный запрос.

Распространённые ошибки

  • Сортировка по строковому столбцу с числами (например, age, хранящийся как VARCHAR) выполняется лексикографически: "10" идёт перед "9". Храните числа в числовом столбце или используйте приведение: ORDER BY CAST(age AS UNSIGNED).
  • ORDER BY с LIMIT — это способ получить «топ N» результатов: ORDER BY age DESC LIMIT 5 вернёт пятерых самых старших. Без ORDER BY строки, которые оставит LIMIT, непредсказуемы. См. ограничение данных.
  • Сортировка большого результирующего набора может быть медленной, если нет индекса по столбцу сортировки; индекс на столбце ORDER BY позволяет MySQL пропустить шаг сортировки.

Заключение

ORDER BY превращает неопределённый порядок строк в определённый. Запомните главное: ASC используется по умолчанию, столбцы применяются слева направо для разрешения равенства, NULL сортируется как меньшее значение, а столбец сортировки, выбранный пользователем, должен проверяться по списку разрешённых значений, а не конкатенироваться слепо. В сочетании с WHERE для фильтрации и LIMIT для постраничного вывода это даёт полный контроль над тем, какие строки возвращаются и в каком порядке.

Практика

Практика
Какова цель оператора ORDER BY в MySQL, описанного на данном сайте?
Какова цель оператора ORDER BY в MySQL, описанного на данном сайте?
Was this page helpful?