【SQL】ORDER BYの使い方|ソート順・NULL制御・複数列・パフォーマンスまで完全解説

【SQL】ORDER BYの使い方|ソート順・NULL制御・複数列・パフォーマンスまで完全解説 SQL

SQLのORDER BY句は、SELECT文の結果を特定の列の値で並べ替える(ソートする)ための句です。昇順(ASC)・降順(DESC)の基本はもちろん、NULLの扱い、CASE式によるカスタムソート、パフォーマンスへの影響など、実務で押さえるべきポイントは多岐にわたります。

この記事では、ORDER BYの基本構文から応用テクニック、RDBMS別の違い、パフォーマンス最適化まで体系的に解説します。

この記事で学べること

  • ORDER BYの基本構文(ASC / DESC / 複数列ソート)
  • NULLのソート順を制御する方法(NULLS FIRST / LAST、MySQL代替策)
  • CASE式・関数を使った柔軟なソート
  • 列番号・エイリアスでのソート指定と注意点
  • MySQL / PostgreSQL / Oracle / SQL Server のRDBMS別の違い
  • ORDER BYとインデックスの関係・パフォーマンス最適化
  • よくあるミスと注意点(GROUP BY・UNION・DISTINCTとの併用)
スポンサーリンク
  1. サンプルデータの準備
  2. ORDER BYの基本構文
    1. 基本構文
    2. ASC(昇順)でソートする
    3. DESC(降順)でソートする
    4. 複数列でソートする
    5. 文字列のソート順について
  3. NULLのソート順を制御する
    1. RDBMS別のNULLデフォルト位置
    2. NULLS FIRST / NULLS LAST(PostgreSQL・Oracle)
    3. MySQLでNULLの位置を制御する
      1. 方法1:ISNULL() を使う
      2. 方法2:COALESCE() を使う
      3. 方法3:CASE式を使う
    4. NULL制御方法のまとめ
  4. 式・関数でソートする
    1. CASE式でカスタム順序を定義する
    2. 文字列の長さでソートする
    3. 日付の一部でソートする
    4. 計算式でソートする
  5. 列番号・エイリアスでソートする
    1. 列番号で指定する(ORDER BY 1, 2)
    2. エイリアス(別名)で指定する
    3. 列番号 vs エイリアス vs 列名の比較
  6. RDBMS別の違い
    1. MySQL固有の機能
      1. FIELD()関数でカスタムソート
      2. COLLATE句で照合順序を指定
    2. PostgreSQL固有の機能
      1. NULLS FIRST / NULLS LAST
      2. 配列のソート
    3. Oracle固有の機能
      1. NLSSORT()で日本語ソート
    4. SQL Server固有の機能
      1. OFFSET-FETCH(ページネーション)
    5. RDBMS別 ORDER BY機能比較表
  7. パフォーマンスの考慮
    1. ORDER BYとインデックスの関係
    2. 複合インデックスとORDER BY
    3. ソートのメモリ使用量
    4. LIMIT / FETCH FIRSTとの組み合わせ
  8. よくあるミスと注意点
    1. ORDER BYなしの結果は順序が保証されない
    2. GROUP BYとORDER BYの併用
    3. UNION + ORDER BYの注意点
    4. DISTINCT + ORDER BYの制約
    5. サブクエリ内のORDER BY
  9. まとめ
    1. ORDER BY 構文パターン早見表

サンプルデータの準備

この記事では以下のテーブルを使って解説します。NULLを含むデータも用意しているので、NULLのソート挙動も確認できます。

▶ CREATE TABLE + INSERT文(クリックで展開)
CREATE TABLE employees (
    id         INT PRIMARY KEY,
    name       VARCHAR(20),
    department VARCHAR(20),
    salary     INT,
    hire_date  DATE,
    rating     VARCHAR(1)
);

INSERT INTO employees VALUES
(1,  '田中太郎',   '営業',   450000, '2020-04-01', 'A'),
(2,  '鈴木花子',   '開発',   520000, '2019-07-15', 'S'),
(3,  '佐藤一郎',   '営業',   380000, '2021-10-01', 'B'),
(4,  '山田美咲',   '人事',   410000, '2020-01-10', 'A'),
(5,  '高橋健太',   '開発',   580000, '2018-04-01', NULL),
(6,  '伊藤真理',   '営業',   420000, '2022-04-01', 'B'),
(7,  '渡辺大輔',   '開発',   490000, '2021-01-15', 'A'),
(8,  '中村さくら', '人事',   350000, '2023-04-01', 'C'),
(9,  '小林誠',     '開発',   550000, '2019-10-01', 'S'),
(10, '加藤由美',   '営業',   NULL,   '2024-01-15', NULL);
id name department salary hire_date rating
1 田中太郎 営業 450000 2020-04-01 A
2 鈴木花子 開発 520000 2019-07-15 S
3 佐藤一郎 営業 380000 2021-10-01 B
4 山田美咲 人事 410000 2020-01-10 A
5 高橋健太 開発 580000 2018-04-01 NULL
6 伊藤真理 営業 420000 2022-04-01 B
7 渡辺大輔 開発 490000 2021-01-15 A
8 中村さくら 人事 350000 2023-04-01 C
9 小林誠 開発 550000 2019-10-01 S
10 加藤由美 営業 NULL 2024-01-15 NULL

ORDER BYの基本構文

ORDER BY句はSELECT文の末尾に記述し、指定した列の値で結果セットを並べ替えます。

基本構文

ORDER BY の基本構文
SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC | DESC]
           [, column2 [ASC | DESC], ...];
キーワード 意味 デフォルト
ASC 昇順(Ascending):小さい値から大きい値へ デフォルト
DESC 降順(Descending):大きい値から小さい値へ

ポイント:ORDER BYを省略すると、結果セットの並び順は保証されません。同じクエリでも実行するたびに順序が変わる可能性があります。確実にソートしたい場合は必ずORDER BYを記述しましょう。

ASC(昇順)でソートする

給与(salary)を昇順で並べ替える例です。ASCはデフォルトのため省略可能ですが、明示的に書くことで意図が明確になります。

SQL
SELECT name, department, salary
FROM employees
ORDER BY salary ASC;
実行結果
name         department  salary
----------   ----------  ------
加藤由美     営業        NULL
中村さくら   人事        350000
佐藤一郎     営業        380000
山田美咲     人事        410000
伊藤真理     営業        420000
田中太郎     営業        450000
渡辺大輔     開発        490000
鈴木花子     開発        520000
小林誠       開発        550000
高橋健太     開発        580000

MySQLでは、NULLは昇順ソート時に先頭に表示されます。NULLの扱いはRDBMSによって異なるため、後述の「NULLのソート順を制御する」セクションで詳しく解説します。

DESC(降順)でソートする

給与を降順(高い順)で並べ替えます。

SQL
SELECT name, department, salary
FROM employees
ORDER BY salary DESC;
実行結果
name         department  salary
----------   ----------  ------
高橋健太     開発        580000
小林誠       開発        550000
鈴木花子     開発        520000
渡辺大輔     開発        490000
田中太郎     営業        450000
伊藤真理     営業        420000
山田美咲     人事        410000
佐藤一郎     営業        380000
中村さくら   人事        350000
加藤由美     営業        NULL

複数列でソートする

ORDER BYにはカンマ区切りで複数の列を指定できます。第1ソートキーが同じ値の場合に、第2ソートキーで並べ替えが行われます。

部署(昇順)→ 給与(降順)でソート
SELECT name, department, salary
FROM employees
ORDER BY department ASC, salary DESC;
実行結果
name         department  salary
----------   ----------  ------
高橋健太     開発        580000
小林誠       開発        550000
鈴木花子     開発        520000
渡辺大輔     開発        490000
田中太郎     営業        450000
伊藤真理     営業        420000
佐藤一郎     営業        380000
加藤由美     営業        NULL
山田美咲     人事        410000
中村さくら   人事        350000

まずdepartmentの昇順で並べ替え、同じ部署内ではsalaryの降順で並べ替えています。各列にASC / DESCを個別に指定できる点がポイントです。

文字列のソート順について

文字列をORDER BYでソートする場合、照合順序(COLLATION)に従って並べ替えられます。

データ型 ソート順の決定方法
数値型(INT, DECIMAL等) 数値の大小で比較
日付型(DATE, TIMESTAMP等) 日付の前後で比較
文字列型(VARCHAR, TEXT等) 照合順序(COLLATION)に依存。大文字小文字の区別、日本語の並び順はCOLLATIONで変わる
NULL RDBMSにより異なる(次セクションで詳しく解説)

NULLのソート順を制御する

ORDER BYでソートする際、NULLをどの位置に表示するかはRDBMSによってデフォルトの挙動が異なります。まずはRDBMS別のデフォルト動作を確認し、その後に制御方法を解説します。

RDBMS別のNULLデフォルト位置

RDBMS ASC時のNULL位置 DESC時のNULL位置 NULLの扱い
MySQL 先頭 末尾 NULLを最小値として扱う
PostgreSQL 末尾 先頭 NULLを最大値として扱う
Oracle 末尾 先頭 NULLを最大値として扱う
SQL Server 先頭 末尾 NULLを最小値として扱う

注意:同じSQLでもRDBMSが異なるとNULLの表示位置が変わります。移植性を考慮する場合は、必ず明示的にNULLの位置を制御しましょう。

NULLS FIRST / NULLS LAST(PostgreSQL・Oracle)

PostgreSQLとOracleでは、ORDER BY句にNULLS FIRSTまたはNULLS LASTを付けることで、NULLの位置を明示的に制御できます。

PostgreSQL / Oracle
-- NULLを末尾に表示(昇順)
SELECT name, salary
FROM employees
ORDER BY salary ASC NULLS LAST;

-- NULLを先頭に表示(降順)
SELECT name, salary
FROM employees
ORDER BY salary DESC NULLS FIRST;

MySQLでNULLの位置を制御する

MySQLにはNULLS FIRST / LAST構文がありません。代わりに以下の方法でNULLの位置を制御します。

方法1:ISNULL() を使う

MySQL – NULLを末尾に移動
SELECT name, salary
FROM employees
ORDER BY ISNULL(salary) ASC, salary ASC;

ISNULL(salary)はNULLなら1、それ以外は0を返します。これを第1ソートキーにすることで、NULLを末尾に移動できます。

方法2:COALESCE() を使う

MySQL – NULLを末尾に移動(COALESCE版)
-- NULLを非常に大きい値に置換して末尾へ
SELECT name, salary
FROM employees
ORDER BY COALESCE(salary, 9999999) ASC;

方法3:CASE式を使う

MySQL – CASE式でNULL制御
SELECT name, salary
FROM employees
ORDER BY
    CASE WHEN salary IS NULL THEN 1 ELSE 0 END,
    salary ASC;
実行結果(いずれの方法も同じ)
name         salary
----------   ------
中村さくら   350000
佐藤一郎     380000
山田美咲     410000
伊藤真理     420000
田中太郎     450000
渡辺大輔     490000
鈴木花子     520000
小林誠       550000
高橋健太     580000
加藤由美     NULL     <-- 末尾に移動

NULL制御方法のまとめ

方法 対応RDBMS 特徴
NULLS FIRST / LAST PostgreSQL, Oracle 最も簡潔で可読性が高い
ISNULL() MySQL シンプルで高速
COALESCE() 全RDBMS 代替値の選択が必要
CASE式 全RDBMS 最も柔軟だがやや冗長

式・関数でソートする

ORDER BYには列名だけでなく、式や関数の結果を指定することもできます。これにより、データベースに格納されていない順序でソートが可能になります。

CASE式でカスタム順序を定義する

評価(rating)を S > A > B > C の順で並べ替えたい場合、アルファベット順では期待通りになりません。CASE式を使って独自のソート順を定義します。

CASE式でカスタムソート
SELECT name, department, rating
FROM employees
ORDER BY
    CASE rating
        WHEN 'S' THEN 1
        WHEN 'A' THEN 2
        WHEN 'B' THEN 3
        WHEN 'C' THEN 4
        ELSE 5
    END;
実行結果
name         department  rating
----------   ----------  ------
鈴木花子     開発        S
小林誠       開発        S
田中太郎     営業        A
山田美咲     人事        A
渡辺大輔     開発        A
佐藤一郎     営業        B
伊藤真理     営業        B
中村さくら   人事        C
高橋健太     開発        NULL
加藤由美     営業        NULL

CASE式のELSEに5を設定しているため、NULLや未定義の評価値は末尾に表示されます。この方法は「ステータス順」「優先度順」など、ビジネスロジックに基づいたソートに非常に便利です。

文字列の長さでソートする

LENGTH()(MySQL / PostgreSQL)やLEN()(SQL Server)を使って、文字列の長さでソートできます。

名前の文字数が多い順にソート
-- MySQL / PostgreSQL
SELECT name, LENGTH(name) AS name_len
FROM employees
ORDER BY LENGTH(name) DESC;

-- SQL Server
SELECT name, LEN(name) AS name_len
FROM employees
ORDER BY LEN(name) DESC;

日付の一部でソートする

入社月(hire_dateの月部分)でソートするなど、日付の一部を使ったソートも可能です。

入社月でソート
-- MySQL
SELECT name, hire_date, MONTH(hire_date) AS hire_month
FROM employees
ORDER BY MONTH(hire_date);

-- PostgreSQL / Oracle
SELECT name, hire_date, EXTRACT(MONTH FROM hire_date) AS hire_month
FROM employees
ORDER BY EXTRACT(MONTH FROM hire_date);
実行結果
name         hire_date    hire_month
----------   ----------   ----------
山田美咲     2020-01-10   1
渡辺大輔     2021-01-15   1
加藤由美     2024-01-15   1
高橋健太     2018-04-01   4
田中太郎     2020-04-01   4
伊藤真理     2022-04-01   4
中村さくら   2023-04-01   4
鈴木花子     2019-07-15   7
小林誠       2019-10-01   10
佐藤一郎     2021-10-01   10

計算式でソートする

列の値を使った計算結果でソートすることもできます。

勤続年数(年)でソート
-- MySQL
SELECT name, hire_date,
       TIMESTAMPDIFF(YEAR, hire_date, CURDATE()) AS years_worked
FROM employees
ORDER BY TIMESTAMPDIFF(YEAR, hire_date, CURDATE()) DESC;

列番号・エイリアスでソートする

ORDER BYでは、列名の代わりに列番号エイリアスを指定することもできます。

列番号で指定する(ORDER BY 1, 2)

SELECT句に記述した列の位置番号(1始まり)を使ってソートを指定できます。

列番号で指定
SELECT department, name, salary
FROM employees
ORDER BY 1 ASC, 3 DESC;
-- ORDER BY department ASC, salary DESC と同じ

注意:列番号によるソートは可読性が低く、保守性も悪いため、実務ではあまり推奨されません。SELECT句の列の順序を変更するとORDER BYの意味も変わってしまいます。アドホックなクエリやちょっとした確認には便利ですが、本番コードでは列名を使いましょう。

エイリアス(別名)で指定する

SELECT句で定義したエイリアスをORDER BYで使えます。

エイリアスでソート
SELECT
    department,
    COUNT(*) AS emp_count,
    AVG(salary) AS avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;
実行結果
department  emp_count  avg_salary
----------  ---------  ----------
開発        4          535000.0000
営業        4          416666.6667
人事        2          380000.0000

集計関数の結果にエイリアスを付けてソートするパターンは、レポート系のクエリで頻繁に使います。

列番号 vs エイリアス vs 列名の比較

指定方法 可読性 保守性 推奨場面
列名 ORDER BY salary 高い 高い 本番コード全般
エイリアス ORDER BY avg_salary 高い 高い 集計結果のソート
列番号 ORDER BY 1, 2 低い 低い アドホッククエリ

RDBMS別の違い

ORDER BYの基本構文は各RDBMSで共通ですが、拡張機能や独自の関数にはそれぞれ違いがあります。

MySQL固有の機能

FIELD()関数でカスタムソート

MySQLのFIELD()関数を使うと、CASE式より簡潔にカスタムソートを記述できます。

MySQL – FIELD()関数
-- 部署を「開発→営業→人事」の順に並べる
SELECT name, department, salary
FROM employees
ORDER BY FIELD(department, '開発', '営業', '人事');

FIELD(値, '候補1', '候補2', ...)は、値が候補リストの何番目にあるかを返します。候補1なら1、候補2なら2を返すので、リストの順序でソートされます。

COLLATE句で照合順序を指定

MySQL – 大文字小文字を区別してソート
-- デフォルトのutf8mb4_general_ciは大文字小文字を区別しない
-- utf8mb4_binを指定すると区別する
SELECT name
FROM employees
ORDER BY name COLLATE utf8mb4_bin;

PostgreSQL固有の機能

NULLS FIRST / NULLS LAST

前述の通り、PostgreSQLではNULLの位置をNULLS FIRST/NULLS LASTで明示的に制御できます。

配列のソート

PostgreSQL – 配列カラムのソート
-- 配列の最初の要素でソート
SELECT name, skills[1] AS primary_skill
FROM staff
ORDER BY skills[1];

Oracle固有の機能

NLSSORT()で日本語ソート

Oracleではデフォルトのソート順がバイナリ順になる場合があり、日本語の五十音順で並べたい場合はNLSSORT()を使います。

Oracle – 日本語の五十音順ソート
SELECT name, department
FROM employees
ORDER BY NLSSORT(name, 'NLS_SORT=JAPANESE_M');

SQL Server固有の機能

OFFSET-FETCH(ページネーション)

SQL ServerではOFFSET-FETCH句を使ってページネーションを実装します。ORDER BYと組み合わせることが必須です。

SQL Server – ページネーション
-- 3件目から5件取得(2ページ目、1ページ5件)
SELECT name, salary
FROM employees
ORDER BY salary DESC
OFFSET 5 ROWS
FETCH NEXT 5 ROWS ONLY;

RDBMS別 ORDER BY機能比較表

機能 MySQL PostgreSQL Oracle SQL Server
NULLS FIRST/LAST
FIELD()関数
COLLATE句
LIMIT
FETCH FIRST n ROWS ✓(8.0+) ✓(12c+)
NLSSORT()

パフォーマンスの考慮

ORDER BYはクエリの結果セット全体をソートするため、大量データを扱う場合はパフォーマンスに大きく影響します。ここではORDER BYのパフォーマンスを改善するためのポイントを解説します。

ORDER BYとインデックスの関係

ORDER BYで指定した列にインデックスがある場合、MySQLはインデックスを使ってソート処理をスキップできます(filesortの回避)。

インデックスを活用したソート
-- salaryにインデックスを作成
CREATE INDEX idx_salary ON employees(salary);

-- このクエリはインデックスを使ってソートできる
SELECT name, salary
FROM employees
ORDER BY salary ASC;

-- EXPLAINで確認(MySQLの場合)
EXPLAIN SELECT name, salary
FROM employees
ORDER BY salary ASC;

インデックスが効くケース・効かないケース

  • 効く:ORDER BYの列がインデックスの先頭列(またはその一部)と一致する場合
  • 効く:WHERE句の条件列 + ORDER BYの列が複合インデックスの順序と一致する場合
  • 効かない:ORDER BYに式・関数を使っている場合(例:ORDER BY UPPER(name))
  • 効かない:ASCとDESCが混在し、インデックスの方向と一致しない場合
  • 効かない:複数テーブルのJOINでORDER BYを使う場合(一部例外あり)

複合インデックスとORDER BY

WHERE句とORDER BY句の両方がある場合、複合インデックスを適切に設計するとソート処理を効率化できます。

複合インデックスの活用
-- WHERE句の列 + ORDER BY句の列で複合インデックスを作成
CREATE INDEX idx_dept_salary
ON employees(department, salary);

-- このクエリはインデックスをフル活用できる
SELECT name, salary
FROM employees
WHERE department = '開発'
ORDER BY salary DESC;

ソートのメモリ使用量

インデックスが使えない場合、データベースはメモリ上でソートを行います(MySQL ではfilesortと呼ばれます)。メモリに収まらない場合はディスクを使うため、処理が大幅に遅くなります。

RDBMS ソート用メモリ設定 デフォルト値
MySQL sort_buffer_size 256KB
PostgreSQL work_mem 4MB
Oracle SORT_AREA_SIZE / PGA_AGGREGATE_TARGET 自動管理
SQL Server max server memory 自動管理

LIMIT / FETCH FIRSTとの組み合わせ

ORDER BYとLIMIT(MySQL / PostgreSQL)やFETCH FIRSTを組み合わせると、上位N件だけを効率的に取得できます。

上位N件の取得(RDBMS別)
-- MySQL / PostgreSQL
SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 3;

-- Oracle 12c+ / SQL Server / PostgreSQL
SELECT name, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 3 ROWS ONLY;

-- Oracle 11g以前
SELECT * FROM (
    SELECT name, salary
    FROM employees
    ORDER BY salary DESC
) WHERE ROWNUM <= 3;
実行結果
name       salary
--------   ------
高橋健太   580000
小林誠     550000
鈴木花子   520000

パフォーマンスのポイント:ORDER BY + LIMIT(FETCH FIRST)のクエリでは、インデックスがあれば全行をソートせずに上位N件だけを取り出せるため、非常に高速です。ランキング系・ページネーション系のクエリでは積極的に活用しましょう。

よくあるミスと注意点

ORDER BYは一見シンプルですが、他の句との組み合わせで思わぬ落とし穴があります。よくあるミスと注意点をまとめます。

ORDER BYなしの結果は順序が保証されない

これは最も重要なポイントです。ORDER BYを記述しないSELECT文の結果セットは、どのような順序で返されるか保証されません

順序が保証されない例
-- 結果の順序は保証されない!
SELECT name, salary FROM employees;

-- 順序を保証するにはORDER BYが必要
SELECT name, salary FROM employees
ORDER BY salary DESC;

たまたまINSERTした順序で返されることが多いですが、テーブルの構造変更やインデックスの追加・削除、データの更新などで順序が変わることがあります。順序に依存するロジックがある場合は、必ずORDER BYを付けましょう。

GROUP BYとORDER BYの併用

GROUP BYORDER BYを一緒に使う場合、ORDER BYに指定できるのはGROUP BYに含まれる列集計関数のみです。

GROUP BY + ORDER BY
-- 正しい例
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;

-- エラーになる例(nameはGROUP BYに含まれない)
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
ORDER BY name;  -- エラー!

注意:MySQLのONLY_FULL_GROUP_BYモードが無効の場合、エラーにならずに実行される場合がありますが、結果は不定です。MySQL 5.7.5以降ではデフォルトでONLY_FULL_GROUP_BYが有効になっているため、上記のようなクエリはエラーになります。

UNION + ORDER BYの注意点

UNIONで複数のSELECT文を結合する場合、ORDER BYは最後のSELECT文の後に1つだけ記述します。

UNION + ORDER BY
-- 正しい例:UNION全体の結果をソート
SELECT name, salary, '正社員' AS emp_type
FROM employees
WHERE salary >= 400000

UNION ALL

SELECT name, salary, '契約社員' AS emp_type
FROM employees
WHERE salary < 400000

ORDER BY salary DESC;  -- UNION全体に適用

個々のSELECT文にORDER BYを付けたい場合は、サブクエリで囲む必要があります(ただし、最終的なUNION全体のORDER BYがないと順序は保証されません)。

UNION内の個別ソートは不可
-- エラーになる例
SELECT name, salary FROM employees
WHERE department = '開発'
ORDER BY salary DESC  -- ここにORDER BYは書けない

UNION ALL

SELECT name, salary FROM employees
WHERE department = '営業'
ORDER BY salary DESC;

DISTINCT + ORDER BYの制約

DISTINCTを使用する場合、ORDER BYにはSELECT句に含まれる列のみ指定できます。

DISTINCT + ORDER BY
-- 正しい例
SELECT DISTINCT department
FROM employees
ORDER BY department;

-- エラーになる例(salaryはSELECT句にない)
SELECT DISTINCT department
FROM employees
ORDER BY salary;  -- エラー!

これはSQLの仕様によるものです。DISTINCTで重複を除去した後の結果セットにはsalary列が存在しないため、その列でソートすることはできません。

サブクエリ内のORDER BY

サブクエリ(FROM句やIN句の中のSELECT文)に記述したORDER BYは、通常無視されます

サブクエリ内のORDER BYは無視される
-- サブクエリ内のORDER BYは無意味
SELECT * FROM (
    SELECT name, salary
    FROM employees
    ORDER BY salary DESC  -- ← 無視される可能性あり
) sub;

-- 正しくは外側でORDER BYを記述
SELECT * FROM (
    SELECT name, salary
    FROM employees
) sub
ORDER BY salary DESC;  -- ← 外側で指定

サブクエリ内のORDER BYが必要なケースは、LIMITと組み合わせて上位N件を絞り込む場合など、限られた場面のみです。

まとめ

ORDER BY句は、SQLの結果セットを意図した順序で並べ替えるための重要な句です。最後に、主要な構文パターンを早見表としてまとめます。

ORDER BY 構文パターン早見表

用途 構文例
昇順ソート ORDER BY salary ASC(ASCは省略可)
降順ソート ORDER BY salary DESC
複数列ソート ORDER BY dept ASC, salary DESC
NULL末尾(PG/Oracle) ORDER BY salary ASC NULLS LAST
NULL末尾(MySQL) ORDER BY ISNULL(salary), salary ASC
カスタムソート(CASE) ORDER BY CASE col WHEN 'A' THEN 1 ... END
カスタムソート(MySQL) ORDER BY FIELD(col, 'A', 'B', 'C')
関数でソート ORDER BY LENGTH(name) DESC
エイリアスでソート ORDER BY avg_salary DESC
列番号でソート ORDER BY 1, 2 DESC
上位N件取得 ORDER BY salary DESC LIMIT 5

実務で意識すべきポイント

  • 順序が必要なクエリには必ずORDER BYを記述する(省略時の順序は不定)
  • NULLを含む列のソートでは、RDBMSごとのデフォルト挙動を理解し、明示的に制御する
  • 大量データのソートではインデックスを活用してfilesortを回避する
  • WHERE句 + ORDER BYの列を複合インデックスにまとめると効率的
  • GROUP BY・UNION・DISTINCTとの併用時は制約に注意する
  • 列番号指定は避け、列名またはエイリアスを使う(可読性・保守性)