【初心者向け】SQLで並び替え(ソート)する方法まとめ

データベース・SQL

SQLでデータを検索した結果が大量に返ってきたとき、順序がバラバラだと読みにくく・使いにくいですよね。

そんなときに活躍するのがORDER BY句です。好きな項目で並び替えて、一覧性や利便性をグッと高めてくれます。

ソートが役立つ場面

  • 売上データを金額の高い順に見たい
  • 社員リストを名前順に整理したい
  • 商品在庫を少ない順に確認したい
  • 成績表を点数順に並べたい
スポンサーリンク

基本構文:ORDER BYの書き方

基本の形

SELECT 列名1, 列名2, ...
FROM テーブル名
ORDER BY 並び替えたい列 [ASC | DESC];

重要なポイント:

  • ASC:昇順(小さい順、あ→ん、A→Z)※省略可能
  • DESC:降順(大きい順、ん→あ、Z→A)

例1:年齢順に並べる(昇順)

-- 年齢の若い人から順に表示
SELECT name, age 
FROM users
ORDER BY age ASC;

実行結果例:

name    | age
--------|----
田中    | 22
佐藤    | 25
山田    | 30
鈴木    | 35

ASCは省略可能:

-- これも同じ結果
SELECT name, age 
FROM users
ORDER BY age;

例2:年齢順に並べる(降順)

-- 年齢の高い人から順に表示
SELECT name, age 
FROM users
ORDER BY age DESC;

実行結果例:

name    | age
--------|----
鈴木    | 35
山田    | 30
佐藤    | 25
田中    | 22

例3:文字列データの並び替え

-- 名前をあいうえお順に並べる
SELECT name, department 
FROM employees
ORDER BY name ASC;

実行結果例:

name     | department
---------|----------
青木     | 営業部
石田     | 開発部
上田     | 営業部
大野     | 総務部

複数条件で並び替える

基本的な考え方

複数の条件を指定すると、最初の条件で並び替えて、同じ値の場合は次の条件で並び替えます。

例1:部署 → 年齢の順に並べる

SELECT name, department, age 
FROM employees
ORDER BY department ASC, age DESC;

実行結果例:

name     | department | age
---------|------------|----
山田     | 営業部     | 35
佐藤     | 営業部     | 28
田中     | 営業部     | 25
鈴木     | 開発部     | 32
青木     | 開発部     | 26

解説:

  1. まず部署名で昇順(あいうえお順)に並び替え
  2. 同じ部署内では年齢で降順(高い順)に並び替え

例2:売上データの並び替え

-- 年月 → 売上金額の順に並べる
SELECT sales_date, product_name, amount 
FROM sales
ORDER BY sales_date DESC, amount DESC;

使い方のコツ:

  • 最初の条件が最も優先される
  • 条件は,(カンマ)で区切る
  • 各条件に個別にASC/DESCを指定できる

例3:3つ以上の条件

-- 地域 → 部署 → 年齢の順
SELECT name, region, department, age 
FROM employees
ORDER BY region ASC, department ASC, age DESC;

列番号で指定する方法

基本的な使い方

-- SELECTの2番目の列(age)で降順ソート
SELECT name, age 
FROM users
ORDER BY 2 DESC;

列番号の対応:

SELECT name, age, department  -- 1番目, 2番目, 3番目
FROM employees
ORDER BY 3, 2 DESC;  -- 部署順、その中で年齢降順

注意点

推奨しない理由:

  • 列の順序を変更するとソート順も変わってしまう
  • 何の列でソートしているかわかりにくい
  • 保守性が低い

良い例と悪い例:

-- 悪い例
ORDER BY 2 DESC

-- 良い例
ORDER BY age DESC

列番号が有効な場面

  • 一時的なデータ確認で手早く並び替えたいとき
  • SELECT文が非常に長い場合の簡略表記

NULLの並び順を制御する

NULLとは?

NULLは「値が存在しない」「未入力」を意味するデータです。

データベース別のNULL処理

データベースNULLの扱い(ASC)NULLの扱い(DESC)
MySQLNULLが最初NULLが最後
PostgreSQLNULLが最後NULLが最初
OracleNULLが最後NULLが最初
SQL ServerNULLが最初NULLが最後

NULL位置の明示的な制御

PostgreSQL、Oracleの場合

-- NULLを最後に配置
SELECT name, age 
FROM users
ORDER BY age ASC NULLS LAST;

-- NULLを最初に配置
SELECT name, age 
FROM users
ORDER BY age DESC NULLS FIRST;

MySQLの場合

-- NULLを最後に配置
SELECT name, age 
FROM users
ORDER BY age IS NULL, age ASC;

-- NULLを最初に配置
SELECT name, age 
FROM users
ORDER BY age IS NULL DESC, age ASC;

実用例

例1:連絡先リストの整理

-- 電話番号が登録済みの人を先に、未登録を後に
SELECT name, phone 
FROM customers
ORDER BY phone IS NULL, name ASC;

実行結果例:

name     | phone
---------|-------------
田中     | 090-1234-5678
山田     | 080-9876-5432
佐藤     | NULL
鈴木     | NULL

例2:商品の価格順リスト

-- 価格が設定されている商品を先に表示
SELECT product_name, price 
FROM products
ORDER BY price IS NULL, price ASC;

応用:他のSQL句との組み合わせ

LIMITと組み合わせて上位N件を取得

例1:成績上位者の取得

-- 点数が高い順に上位5名を取得
SELECT name, score 
FROM students
ORDER BY score DESC
LIMIT 5;

実行結果例:

name     | score
---------|------
山田     | 95
田中     | 92
佐藤     | 88
鈴木     | 85
青木     | 82

例2:最新の投稿を取得

-- 最新の投稿10件を取得
SELECT title, created_at 
FROM posts
ORDER BY created_at DESC
LIMIT 10;

例3:売上トップ商品の取得

-- 今月の売上トップ3商品
SELECT product_name, SUM(amount) as total_sales
FROM sales
WHERE MONTH(sales_date) = MONTH(CURRENT_DATE)
GROUP BY product_name
ORDER BY total_sales DESC
LIMIT 3;

WHEREと組み合わせた絞り込み

-- 営業部の社員を年齢順に表示
SELECT name, age, department 
FROM employees
WHERE department = '営業部'
ORDER BY age ASC;

GROUP BYと組み合わせた集計結果の並び替え

-- 部署別の平均年齢を高い順に表示
SELECT department, AVG(age) as avg_age
FROM employees
GROUP BY department
ORDER BY avg_age DESC;

SQL文の正しい順序

基本的な順序

SELECT 列名
FROM テーブル名
WHERE 条件
GROUP BY グループ化する列
HAVING グループ化後の条件
ORDER BY 並び替える列
LIMIT 取得件数;

順序を間違えた場合のエラー

-- ❌ 間違い:ORDER BYがWHEREより前
SELECT name, age 
FROM users
ORDER BY age DESC
WHERE age >= 20;  -- エラーになる

-- ✅ 正しい:WHEREの後にORDER BY
SELECT name, age 
FROM users
WHERE age >= 20
ORDER BY age DESC;

実用例:複雑なクエリ

-- 2023年の売上データから、部署別売上を計算し、
-- 1000万円以上の部署を売上順に表示
SELECT 
    department,
    SUM(amount) as total_sales
FROM sales s
JOIN employees e ON s.employee_id = e.id
WHERE YEAR(s.sales_date) = 2023
GROUP BY department
HAVING SUM(amount) >= 10000000
ORDER BY total_sales DESC;

実務でよく使うパターン

パターン1:日付データの並び替え

最新順(新しい日付から)

-- 最新の注文から表示
SELECT order_id, customer_name, order_date
FROM orders
ORDER BY order_date DESC;

古い順(過去の日付から)

-- 古い注文から表示
SELECT order_id, customer_name, order_date
FROM orders
ORDER BY order_date ASC;

月別での並び替え

-- 月別売上を月順に表示
SELECT 
    MONTH(order_date) as month,
    SUM(amount) as monthly_sales
FROM orders
WHERE YEAR(order_date) = 2023
GROUP BY MONTH(order_date)
ORDER BY month ASC;

パターン2:文字列データの並び替え

五十音順(あいうえお順)

-- 顧客名を五十音順で表示
SELECT customer_name, phone
FROM customers
ORDER BY customer_name ASC;

アルファベット順

-- 商品コードを昇順で表示
SELECT product_code, product_name
FROM products
ORDER BY product_code ASC;

パターン3:数値データの並び替え

売上ランキング

-- 社員別売上ランキング
SELECT 
    employee_name,
    SUM(amount) as total_sales
FROM sales
GROUP BY employee_name
ORDER BY total_sales DESC;

在庫少ない順

-- 在庫が少ない商品から表示(発注優先度)
SELECT product_name, stock_quantity
FROM products
WHERE stock_quantity > 0
ORDER BY stock_quantity ASC;

パターン4:複合条件での実用例

顧客管理システム

-- 地域別、契約金額順の顧客リスト
SELECT 
    customer_name,
    region,
    contract_amount,
    contract_date
FROM customers
WHERE contract_amount > 0
ORDER BY region ASC, contract_amount DESC, contract_date DESC;

従業員管理システム

-- 部署別、役職別、入社年数順の従業員リスト
SELECT 
    name,
    department,
    position,
    hire_date,
    DATEDIFF(CURRENT_DATE, hire_date) / 365 as years_of_service
FROM employees
ORDER BY 
    department ASC,
    position DESC,
    hire_date ASC;

パフォーマンスを考慮したソート

インデックスの活用

インデックスが効く場合

-- age列にインデックスがある場合、高速
SELECT name, age 
FROM users
ORDER BY age;

インデックスが効かない場合

-- 計算結果でのソートは遅い
SELECT name, age 
FROM users
ORDER BY age * 2 + 10;

大量データでの注意点

LIMIT を使った効率化

-- 悪い例:全データを並び替えてから上位10件
SELECT name, score 
FROM students
ORDER BY score DESC;  -- 全データソート後、アプリで10件取得

-- 良い例:データベース内で上位10件に絞る
SELECT name, score 
FROM students
ORDER BY score DESC
LIMIT 10;  -- データベース内で10件に絞る

複合インデックスの活用

-- department, age の複合インデックスがある場合
SELECT name, department, age
FROM employees
ORDER BY department, age;  -- 高速

エラーが起きやすいパターンと対処法

エラー1:列名の間違い

-- ❌ 存在しない列でソート
SELECT name, age 
FROM users
ORDER BY ages;  -- 'ages'は存在しない

-- ✅ 正しい列名を使用
SELECT name, age 
FROM users
ORDER BY age;

エラー2:GROUP BYとの組み合わせミス

-- ❌ GROUP BYにない列でソート
SELECT department, COUNT(*)
FROM employees
GROUP BY department
ORDER BY name;  -- nameはGROUP BYにない

-- ✅ GROUP BYに含まれる列か集計関数を使用
SELECT department, COUNT(*) as emp_count
FROM employees
GROUP BY department
ORDER BY emp_count DESC;

エラー3:データ型の不一致

-- ❌ 文字列として保存された数値のソート
-- '1', '10', '2' → '1', '10', '2' (文字列順)

-- ✅ 数値として変換してソート
SELECT product_code 
FROM products
ORDER BY CAST(product_code AS INTEGER);

データベース固有の機能

MySQL固有の機能

FIELD関数による任意順序

-- 指定した順序で並び替え
SELECT name, status 
FROM tasks
ORDER BY FIELD(status, '緊急', '高', '中', '低');

日本語の並び替え

-- 日本語を正しく並び替え
SELECT name 
FROM customers
ORDER BY name COLLATE utf8mb4_ja_0900_as_cs;

PostgreSQL固有の機能

CASE文での条件付きソート

-- ステータス別の優先順位でソート
SELECT task_name, status, priority
FROM tasks
ORDER BY 
    CASE status
        WHEN '緊急' THEN 1
        WHEN '高' THEN 2
        WHEN '中' THEN 3
        WHEN '低' THEN 4
        ELSE 5
    END,
    priority DESC;

Oracle固有の機能

日本語の読み順ソート

-- ひらがな読み順で並び替え
SELECT name 
FROM customers
ORDER BY NLSSORT(name, 'NLS_SORT=JAPANESE_M');

まとめ:ORDER BYの使い分け

並び替えたい内容SQL構文例使用場面
昇順ORDER BY 列名 ASC古い順、小さい順、あいうえお順
降順ORDER BY 列名 DESC新しい順、大きい順、ランキング
複数条件ORDER BY 列1 ASC, 列2 DESCカテゴリ別にまとめて詳細ソート
NULL制御ORDER BY 列名 ASC NULLS LASTデータ品質を考慮した表示
上位取得ORDER BY 列名 DESC LIMIT Nランキング、ベスト○○

コメント

タイトルとURLをコピーしました