MySQL: SELECT DISTINCT / UNIQUEで重複行を除外しつつ、すべての列を返す方法
MySQL: DISTINCT/UNIQUEで重複行を除外しつつ、すべての列を返す方法
SELECT DISTINCT
は、テーブルから重複行を除外して結果を返す便利な機能です。しかし、デフォルトでは指定した列のみが返され、その他の列は省略されます。すべての列を DISTINCT と同様に重複除去しながら返したい場合は、いくつかの方法があります。
方法
例
# すべての列を DISTINCT と同様に重複除去して返す
# 方法 1: SELECT *
SELECT *
FROM テーブル名;
# 方法 2: SELECT で個別に列を指定
SELECT DISTINCT 列1, 列2, ..., 列N, *
FROM テーブル名;
# 方法 3: サブクエリ
SELECT *
FROM (
SELECT DISTINCT 列1, 列2, ..., 列N
FROM テーブル名
) AS サブクエリ名;
# 方法 4: GROUP BY
SELECT *
FROM テーブル名
GROUP BY 列1, 列2, ..., 列N;
補足
SELECT DISTINCT
とSELECT UNIQUE
は、重複行を除外するという意味では同じですが、UNIQUE
はインデックスを利用するため、処理速度が速くなる可能性があります。GROUP BY
を使用する場合は、GROUP BY 句で指定した列が重複行の判定基準になります。
用語解説
- SELECT: テーブルからデータを取得する
- DISTINCT: 重複行を除外する
- UNIQUE: 一意性を保証する
- サブクエリ: 別のクエリを内包したクエリ
- GROUP BY: 列をグループ化する
上記の方法は、MySQL だけでなく、他の多くのデータベースでも使用できます。
-- テーブル employees のサンプルデータ
CREATE TABLE employees (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
department VARCHAR(255) NOT NULL,
salary INT NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO employees (name, department, salary)
VALUES
('山田太郎', '営業', 300000),
('佐藤花子', '開発', 400000),
('田中一郎', '営業', 300000),
('斎藤二郎', '開発', 400000),
('高橋三郎', '営業', 350000);
-- 方法 1: SELECT *
SELECT *
FROM employees;
-- 方法 2: SELECT で個別に列を指定
SELECT DISTINCT name, department, salary
FROM employees;
-- 方法 3: サブクエリ
SELECT *
FROM (
SELECT DISTINCT name, department, salary
FROM employees
) AS t;
-- 方法 4: GROUP BY
SELECT *
FROM employees
GROUP BY name, department;
| id | name | department | salary |
|-----|-----------|------------|---------|
| 1 | 山田太郎 | 営業 | 300000 |
| 2 | 佐藤花子 | 開発 | 400000 |
| 3 | 田中一郎 | 営業 | 300000 |
| 4 | 斎藤二郎 | 開発 | 400000 |
| 5 | 高橋三郎 | 営業 | 350000 |
| name | department | salary |
|-----------|------------|---------|
| 山田太郎 | 営業 | 300000 |
| 佐藤花子 | 開発 | 400000 |
| 田中一郎 | 営業 | 300000 |
| 斎藤二郎 | 開発 | 400000 |
| 高橋三郎 | 営業 | 350000 |
| name | department | salary |
|-----------|------------|---------|
| 山田太郎 | 営業 | 300000 |
| 佐藤花子 | 開発 | 400000 |
| 田中一郎 | 営業 | 300000 |
| 斎藤二郎 | 開発 | 400000 |
| 高橋三郎 | 営業 | 350000 |
| name | department | salary |
|-----------|------------|---------|
| 山田太郎 | 営業 | 300000 |
| 佐藤花子 | 開発 | 400000 |
| 田中一郎 | 営業 | 300000 |
| 斎藤二郎 | 開発 | 400000 |
| 高橋三郎 | 営業 | 350000 |
上記の例では、employees
テーブルというサンプルテーブルを用意し、4つの方法で重複行を除外してすべての列を取得しています。
実行方法
上記
他の方法
CASE
式を使用し、重複行かどうかを判定して、重複行の場合は NULL を返す方法です。
SELECT
name,
department,
salary,
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY name, department ORDER BY salary DESC) > 1 THEN NULL
ELSE salary
END AS salary_without_duplicates
FROM employees;
CTE (Common Table Expressions)
CTE を使用し、重複行を除外した中間テーブルを作成してから、そのテーブルからすべての列を取得する方法です。
WITH t AS (
SELECT
name,
department,
salary,
ROW_NUMBER() OVER (PARTITION BY name, department ORDER BY salary DESC) AS rn
FROM employees
)
SELECT
name,
department,
salary
FROM t
WHERE rn = 1;
外部結合を使用し、重複行かどうかを判定する方法です。
SELECT
e1.name,
e1.department,
e1.salary
FROM employees AS e1
LEFT JOIN employees AS e2
ON e1.name = e2.name
AND e1.department = e2.department
AND e1.salary < e2.salary
WHERE e2.name IS NULL;
- どの方法を使用するかは、パフォーマンス、可読性、複雑性などを考慮して決定する必要があります。
- CASE 式: 条件に応じて異なる値を返す式
- 外部結合: 複数のテーブルを結合する際に、すべての行を返す結合
sql select distinct