MySQLは、対応する他の列とともに、1つの列DISTINCTを選択します


192
ID   FirstName   LastName
1      John        Doe
2      Bugs        Bunny
3      John        Johnson

DISTINCTから結果を選択したいのですFirstNameが、対応するIDおよびが必要LastNameです。

結果セットは1つだけを表示する必要がありますJohnID、a LastNameは1、a はDoeです。


1
あなたは明確なファーストネームを持つ最も低いIDに属するラストネームが欲しいですか?
Thomas Langston、

3
一番上のものの選択に入る論理は何ですか?ジョンドーとジョンジョンソンの両方が2人の異なるジョンであるため、両方を表示してほしいと思いますが、それは私だけです。
judda

4
DISTINCT関数ではありません。の答えDISTINCT()はすべて間違っています。後に配置しないとエラーが表示されますSELECT
質問のオーバーフロー

1
ALL 「distinct」という単語の後に括弧を使用して答えるのは、本当に間違っています。Distinctは関数ではないため、パラメーターを受け入れることができません。distinctに続く括弧は単に無視されます。あなたは括弧は、「複合データ型」を形成しますPostgreSQLの使用している場合を除き
Used_By_Already

回答:


192

このクエリを試してください

 SELECT ID, FirstName, LastName FROM table GROUP BY(FirstName)

15
どの行が返されるかをどうやって知るのですか?
William Entriken 2013

26
MySQL ドキュメントによると、@ Full Decentはできません。「サーバーは各グループから任意の値を自由に選択できるため、それらが同じでない限り、選択された値は不確定です。」実際、私はORDER BY句でこの種のクエリを正常に使用しました。たとえば、ORDER BY id ASC / DESCを追加すると、クエリを実行するたびにMySQLが一貫した結果を返します。しかし、私は誰もが文書化されていない機能を本番環境で使用するべきかどうか確信しています。
Arunas Junevicius 2013年

2
OPはmysqlのバージョンについて言及していません。
diEcho 2013年

2
@sinazaは、5.7.5+変更されたGROUP BY処理
fyrye

3
これは、only_full_group_byモードでは機能しません。IDもLastNameも集約されず、グループ化関数の一部にもならないためです。助けて!
ihodonald

63

このDISTINCTキーワードは、期待したとおりに機能しません。使用SELECT DISTINCT col1, col2, col3すると、実際にはすべての一意の{col1、col2、col3}タプルが選択されます。


14
これをブライアンに指摘してくれてありがとう。GROUP BYを使用して同じ結果を得る方法の例を提供できますか?
mr

59

使用する際に潜在的に予期しない結果を避けるためにGROUP BY、集計機能なしとして受け入れ答えに使用されている MySQLは取得して自由であるため、いかなる集約関数を使用していないときにグループ化されたデータセット内の値を[原文]とし、問題ONLY_FULL_GROUP_BY。除外結合の使用を検討してください。

除外結合-明確なエンティティ

firstnameとlastnameが一意にインデックス付けされている(あいまいでない)と仮定すると、の代わりにをGROUP BY使用して並べ替えをLEFT JOIN行い、結果セットをフィルター処理することもできます。これは、除外JOINとも呼ばれます。

デモを見る

昇順(AZ)

AZから姓で並べられた個別の名を取得するには

クエリ

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname > t2.lastname
WHERE t2.id IS NULL;

結果

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  1 |      John |      Doe |

降順(ZA)

ZAから姓で並べられた固有の名を取得するには

クエリ

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname < t2.lastname
WHERE t2.id IS NULL;

結果

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  3 |      John |  Johnson |

その後、結果のデータを必要に応じて注文できます。


除外結合-あいまいなエンティティ

姓と名の組み合わせが一意ではなく(あいまい)、同じ値の行が複数ある場合は、JOIN条件にOR条件を含めて結果セットをフィルタリングし、IDでフィルタリングすることもできます。

デモを見る

table_nameデータ

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson'),
(4, 'John', 'Doe'),
(5, 'John', 'Johnson')

クエリ

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND (t1.lastname > t2.lastname
OR (t1.firstname = t1.firstname AND t1.lastname = t2.lastname AND t1.id > t2.id))
WHERE t2.id IS NULL;

結果

| id | firstname | lastname |
|----|-----------|----------|
|  1 |      John |      Doe |
|  2 |      Bugs |    Bunny |

順序付きサブクエリ

編集

順序付けられたサブクエリを使用した私の元の回答は、MySQL 5.7.5より前に作成されました。ONLY_FULL_GROUP_BY。代わりに、上記の除外結合の例を使用してください。

注意することも重要です。ONLY_FULL_GROUP_BYが無効になっている場合(MySQL 5.7.5より前の元の動作)GROUP BYMySQLはグループ化されているデータセット内の任意の値を自由に選択できるため、集計関数なしでを使用すると、予期しない結果が生じる可能性があります[sic]

意味ID又はlastname値が取得されてもよい関連付けられていないことを検索さとfirstname行。


警告

MySQLをGROUP BY使用すると、期待どおりの結果が得られない場合がありますORDER BY

テストケースの例を見る

期待される結果を保証するための最良の実装方法は、順序付けられたサブクエリを使用して結果セットのスコープをフィルタリングすることです。

table_nameデータ

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson')

クエリ

SELECT * FROM (
    SELECT * FROM table_name ORDER BY ID DESC
) AS t1
GROUP BY FirstName

結果

| ID | first |    last |
|----|-------|---------|
|  2 |  Bugs |   Bunny |
|  3 |  John | Johnson |

比較

GROUP BYと組み合わせて使用した場合の予期しない結果を示すにはORDER BY

クエリ

SELECT * FROM table_name GROUP BY FirstName ORDER BY ID DESC

結果

| ID | first |  last |
|----|-------|-------|
|  2 |  Bugs | Bunny |
|  1 |  John |   Doe |

3
はるかに完全な答え。最初のクエリで「ID desc」を「ID asc」に変更すると、「John Doe」または「John Johnson」のいずれかを取得できます。2番目のクエリで「ID desc」を変更しても、この効果はありません。
carla

postgresでは、mysqlが不明なため、グループ内のIDが必要です。
Sachin Prasad

1つのSELECTステートメントのGROUP BY column-A ORDER BY column-Bは、最新バージョンのMyriaDBで常に正しく機能しますか?
ニールデイビス

@NealDavis MariaDBマニュアルによるとOrdering is done after grouping.、このユースケースではないので、MariaDBは (SQL標準に従って)サブクエリ内のORDER BYを無視しますLIMIT。あなたは、使用したいと思うWindow Functionあなたは、あなたの質問をする必要があり、より明確にするためのDBA stackexchangeこれは、MySQLに関する質問ですと、
fyrye

1
@NateSいいえ、GROUP BY特定の値を強制するためにそれらの列で集計関数が使用されない限り、グループ化されたデータセット内の任意の値を選択できます。だから、lastnameまたはid注文した行のいずれかから来ることができます。元のサブクエリの例は、デフォルトでMySQL <= 5.7.4は問題ありませんでしたが、技術的にはまだ問題があります。一方でORDER BYランダムな選択を防止するための支援を行い、それはまだ理論的には可能ですが、使用しない場合よりも大幅に少ない確率でORDER BYサブクエリを。
fyrye 2018



3

いかがですか

`SELECT 
    my_distinct_column,
    max(col1),
    max(col2),
    max(col3)
    ...
 FROM
    my_table 
 GROUP BY 
    my_distinct_column`

2

MySQLでこれを実行できるかどうかはわかりませんが、T-SQLでCTEを使用できます

; WITH tmpPeople AS (
 SELECT 
   DISTINCT(FirstName),
   MIN(Id)      
 FROM People
)
SELECT
 tP.Id,
 tP.FirstName,
 P.LastName
FROM tmpPeople tP
JOIN People P ON tP.Id = P.Id

それ以外の場合は、一時テーブルを使用する必要があります。


1

fyryeが指摘したように、受け入れられた回答ONLY_FULL_GROUP_BYは、まだ導入されていない古いバージョンのMySQLに関係しています。MySQL 8.0.17(この例で使用)では、無効にしない限りONLY_FULL_GROUP_BY、次のエラーメッセージが表示されます。

mysql> SELECT id, firstName, lastName FROM table_name GROUP BY firstName;

エラー1055(42000):SELECTリストの式#1がGROUP BY句になく、GROUP BY句の列に機能的に依存しない非集計列 'mydatabase.table_name.id'が含まれています。これはsql_mode = only_full_group_byと互換性がありません

fyryeでは言及されていませんが、https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.htmlで説明されているこれを回避する1つの方法はANY_VALUE()、次の列に関数を適用することですないでGROUP BY句(idおよびlastNameこの例では):

mysql> SELECT ANY_VALUE(id) as id, firstName, ANY_VALUE(lastName) as lastName FROM table_name GROUP BY firstName;
+----+-----------+----------+
| id | firstName | lastName |
+----+-----------+----------+
|  1 | John      | Doe      |
|  2 | Bugs      | Bunny    |
+----+-----------+----------+
2 rows in set (0.01 sec)

前述のドキュメントに書かれているように、

この場合、MySQLは各名前グループ内のアドレス値の非決定性を無視し、クエリを受け入れます。これは、グループごとに非集計列のどの値が選択されるかを単に気にしない場合に役立ちます。やANY_VALUE()などの関数とは異なり、は集約関数ではありません。それは単に非決定性のテストを抑制する働きをします。SUM()COUNT()


明確にするためにANY_VALUE()、私の回答とコメントは曖昧で予測不可能な結果セットの防止に焦点を当てているため、使用を提案することは特に避けました。関数名が示すように、選択された行から任意の値が取得される可能性があります。MAXまたはMIN代わりに使用することをお勧めします。
fyrye

0

MySQLはgroup byおよびorder byを使用する場合に注意してください。MySQLは、selectステートメントの一部ではない列をgroup byおよび/またはorder byピースで使用できる唯一のデータベースです。

したがって、例:column2で表グループからcolumn1を選択し、column3で順序付ける

Postgres、Oracle、MSSQLなどの他のデータベースでは飛ぶことはありません。これらのデータベースで次のことを行う必要があります。

column2で表グループからcolumn1、column2、column3を選択し、column3で順序付け

現在のコードを別のデータベースに移行したり、別のデータベースで作業を開始してコードを再利用したりする場合に備えて、いくつかの情報のみを提供します。


-2

group byを使用して、個別の値と対応するフィールドを表示できます。

select * from tabel_name group by FirstName

これで、次のような出力が得られました。

ID    FirstName     LastName
2     Bugs          Bunny
1     John          Doe


のように答えたい場合

ID    FirstName     LastName
1     John          Doe
2     Bugs          Bunny

次に、このクエリを使用し、

select * from table_name group by FirstName order by ID

2
これは、order byでグループ化したときに常に期待される結果をもたらすとは限りません
fyrye


-4
SELECT DISTINCT (column1), column2
FROM table1
GROUP BY column1

1
DISTINCT()関数ではありません。また、DISTINCTとGROUP BYは同じことをしているため、両方を使用する理由はありません。
Marki555 2015

これは効率的なステートメントではありません。DISTINCTまたはGroup Byのいずれかを使用する必要があります。
heshanlk 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.