> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL の SELECT DISTINCT

> MySQL で SELECT DISTINCT が重複行を取り除く仕組み、それが 1 つの列ではなく選択リスト全体に適用される理由、およびそれが並べ替えないもの。

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

`SELECT DISTINCT` は、各結果行が何回現れても、それを 1 回だけ返します。
「この列にはどんな値が現れるか」という形の質問に答えるもので、これは初めて
見るテーブルについて最初に知りたいことであることが多いものです。

始める前に、`mysql -u root -p sakila` でクライアントを開いてください。

## DISTINCT の仕組み

```sql theme={null}
SELECT DISTINCT COLUMN_LIST
FROM TABLE_NAME;
```

`COLUMN_LIST` を欲しい列に、`TABLE_NAME` をテーブルに置き換えます。
`DISTINCT` は `SELECT` の直後に置かれ、隣の列ではなく選択リスト全体に適用
されます。この 1 つの事実が、これに関するほとんどの驚きを説明します。

## 例

### 1 つの列の値

Sakila はすべての映画にレーティングを付けています。これはどのレーティングが
存在するかを尋ねます。

```sql theme={null}
SELECT DISTINCT rating FROM film;
```

```text theme={null}
+--------+
| rating |
+--------+
| PG     |
| G      |
| NC-17  |
| PG-13  |
| R      |
+--------+
5 rows in set (0.00 sec)
```

1,000 本の映画にわたって 5 つのレーティングです。役に立つ順序では返って
きません。`DISTINCT` は重複を取り除くだけで、順序については何も言わないため
です。順序が欲しいときは `ORDER BY` を追加してください。

### 別の列

```sql theme={null}
SELECT DISTINCT rental_rate FROM film;
```

```text theme={null}
+-------------+
| rental_rate |
+-------------+
|        0.99 |
|        4.99 |
|        2.99 |
+-------------+
3 rows in set (0.00 sec)
```

カタログ内のすべての映画は、3 つの料金のいずれかで価格が付けられています。

### 異なる組み合わせ

2 つの列を指定すると、各列の値を別々に得るのではなく、異なる組み合わせを
それぞれ得ます。

```sql theme={null}
SELECT DISTINCT rating, rental_rate
FROM film
ORDER BY rating, rental_rate;
```

```text theme={null}
+--------+-------------+
| rating | rental_rate |
+--------+-------------+
| G      |        0.99 |
| G      |        2.99 |
| G      |        4.99 |
| PG     |        0.99 |
| PG     |        2.99 |
| PG     |        4.99 |
| PG-13  |        0.99 |
| PG-13  |        2.99 |
| PG-13  |        4.99 |
| R      |        0.99 |
| R      |        2.99 |
| R      |        4.99 |
| NC-17  |        0.99 |
| NC-17  |        2.99 |
| NC-17  |        4.99 |
+--------+-------------+
15 rows in set (0.00 sec)
```

5 つのレーティングに 3 つの料金を掛けると 15 で、たまたますべての組み合わせが
存在します。

## 並べ替えたレーティングがアルファベット順でない理由

その結果は `rating` で並べ替えられていますが、`G`、`PG`、`PG-13`、`R`、`NC-17`
の順に並んでいます。アルファベット順なら `NC-17` は 2 番目に来るはずです。
`ORDER BY` は正しく動作しており、その理由は列の型にあります。

`SHOW COLUMNS` はテーブルの列を一覧にし、`LIKE` の後のパターンがそれを 1 つの
名前に絞り込みます。

```sql theme={null}
SHOW COLUMNS FROM film LIKE 'rating';
```

```text theme={null}
+--------+------------------------------------+------+-----+---------+-------+
| Field  | Type                               | Null | Key | Default | Extra |
+--------+------------------------------------+------+-----+---------+-------+
| rating | enum('G','PG','PG-13','R','NC-17') | YES  |     | G       |       |
+--------+------------------------------------+------+-----+---------+-------+
1 row in set (0.00 sec)
```

`rating` は `ENUM` で、固定された値のリストだけを受け入れる列型です。MySQL は
各値をそのリスト内の位置として保存し、その位置で並べ替えるため、`ENUM` は値が
宣言された順序で並びます。ここでは、宣言された順序は最も制限の緩いレーティング
から最も厳しいものへと並んでいます。

## 列を追加すると効果がなくなることがある

`DISTINCT` は行全体を見るため、ほぼ一意な列を追加すると、ほとんど何も
取り除かれません。

```sql theme={null}
SELECT DISTINCT rating, title FROM film;
```

```text theme={null}
+--------+-----------------------------+
| rating | title                       |
+--------+-----------------------------+
| PG     | ACADEMY DINOSAUR            |
| G      | ACE GOLDFINGER              |
| NC-17  | ADAPTATION HOLES            |
...
+--------+-----------------------------+
1000 rows in set (0.00 sec)
```

1,000 行すべてが返ります。各タイトルは異なるため、`rating` と `title` の各
組み合わせも異なり、重複するものは何もありません。ここで `DISTINCT` が 5 行を
返すことはできません。1,000 個の異なる値を持つ列を求めたからです。多くの行を
レーティングごとに 1 行にまとめるのは別の操作であり、
[GROUP BY](https://villagesql.com/docs/ja/tutorial/group-by.md) がそのための句です。

## まとめ

* 各結果行を 1 回だけ返すには `SELECT DISTINCT` を使います。
* 選択リスト内のすべての列に同時に適用されると考えてください。
* 重複を除いた値を並べ替えたいときは `ORDER BY` を追加します。
* `ENUM` 列はアルファベット順ではなく宣言された順序で並ぶと考えてください。

## 関連項目

* [SELECT](https://villagesql.com/docs/ja/tutorial/select.md) — DISTINCT が修飾する文
* [ORDER BY](https://villagesql.com/docs/ja/tutorial/order-by.md) — 重複を除いた値の並べ替え
* [GROUP BY](https://villagesql.com/docs/ja/tutorial/group-by.md) — 行を値ごとに 1 行にまとめ、件数を付ける


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.