MySQL pilih satu kolom DISTINCT, dengan kolom lainnya yang sesuai

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

Saya ingin memilih DISTINCThasil dari FirstNamekolom, tetapi saya perlu yang sesuai IDdan LastName.

Set hasil harus menunjukkan hanya satu John, tetapi dengan angka ID1 dan LastNameDoe.

Bapak
sumber
1
Anda ingin nama belakang milik ID terendah dengan nama depan yang berbeda?
Thomas Langston
3
Apa logika yang harus masuk ke pemilihan yang paling atas? Saya pikir Anda ingin John Doe dan John Johnson muncul karena mereka adalah dua John yang berbeda tetapi hanya saya.
judda
4
DISTINCTbukan fungsi. Semua jawaban DISTINCT()salah. Kesalahan akan muncul ketika Anda tidak menempatkannya setelahnya SELECT.
Pertanyaan Overflow
1
ALL jawaban menggunakan tanda kurung setelah kata berbeda memang salah. Perbedaan BUKAN fungsi sehingga tidak dapat menerima parameter. Tanda kurung berikut berbeda hanya diabaikan. Kecuali jika Anda menggunakan PostgreSQL tempat tanda kurung akan membentuk "tipe data kompleks"
Used_By_Already

Jawaban:

192

coba kueri ini

 SELECT ID, FirstName, LastName FROM table GROUP BY(FirstName)
diEcho
sumber
15
Bagaimana kita tahu baris mana yang akan dikembalikan?
William Entriken
26
@Full Layak Anda tidak dapat, menurut dokumentasi MySQL : "Server bebas untuk memilih nilai apa pun dari setiap grup, jadi kecuali mereka sama, nilai yang dipilih tidak pasti.". Dalam praktiknya saya telah berhasil menggunakan pertanyaan semacam ini dengan klausa ORDER BY, misalnya Anda bisa menambahkan ORDER BY id ASC / DESC dan MySQL akan mengembalikan hasil yang konsisten setiap kali Anda menjalankan kueri. Tetapi saya akan yakin apakah ada orang yang harus menggunakan fitur tidak berdokumen di lingkungan produksi.
Arunas Junevicius
2
OP tidak menyebutkan versi mysql.
diEcho
2
@sinaza lihat jawaban saya yang diperbarui untuk MySQL 5.7.5+untuk GROUP BYpenanganan yang
fyrye
3
Ini tidak berfungsi dengan mode only_full_group_by karena ID atau LastName tidak diagregasi maupun bagian dari fungsi pengelompokan. Tolong!
ihodonald
63

Kata DISTINCTkunci tidak benar-benar berfungsi seperti yang Anda harapkan. Ketika Anda menggunakan SELECT DISTINCT col1, col2, col3Anda sebenarnya memilih semua tupel {col1, col2, col3} yang unik.

Brian Driscoll
sumber
14
Terima kasih telah menunjukkan ini pada Brian. Bisakah Anda memberikan contoh bagaimana saya bisa menggunakan GROUP BY untuk mendapatkan hasil yang sama?
mr
59

Untuk menghindari kemungkinan hasil yang tidak terduga ketika menggunakan GROUP BYtanpa fungsi agregat, seperti yang digunakan dalam jawaban yang diterima , karena MySQL bebas untuk mengambil nilai APAPUN dalam kumpulan data yang dikelompokkan ketika tidak menggunakan fungsi agregat [sic] dan masalah dengan ONLY_FULL_GROUP_BY. Harap pertimbangkan untuk menggunakan gabungan pengecualian.

Pengecualian Bergabung - Entitas yang Tidak Mendua

Dengan asumsi nama depan dan nama belakang diindeks secara unik (tidak ambigu) , alternatifnya GROUP BYadalah menyortir menggunakan LEFT JOINuntuk menyaring set hasil, atau dikenal sebagai pengecualian. GABUNG.

Lihat Demonstrasi

Pesanan naik (AZ)

Untuk mengambil nama depan berbeda yang dipesan oleh nama belakang dari AZ

Pertanyaan

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;

Hasil

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

Urutan menurun (ZA)

Untuk mengambil nama depan berbeda yang dipesan oleh nama belakang dari ZA

Pertanyaan

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;

Hasil

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

Anda kemudian dapat memesan data yang dihasilkan sesuai keinginan.


Pengecualian Bergabung - Entitas Mendua

Jika kombinasi nama depan dan belakang tidak unik (ambigu) dan Anda memiliki beberapa baris dengan nilai yang sama, Anda dapat memfilter hasil yang ditetapkan dengan menyertakan kondisi ATAU pada kriteria GABUNG untuk juga memfilter menurut id.

Lihat Demonstrasi

data table_name

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

Pertanyaan

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;

Hasil

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

Subquery Dipesan

EDIT

Jawaban asli saya menggunakan subquery yang dipesan , ditulis sebelum MySQL 5.7.5 , yang tidak lagi berlaku, karena perubahan denganONLY_FULL_GROUP_BY . Silakan gunakan pengecualian gabungan contoh di atas saja.

Penting juga untuk dicatat; ketika ONLY_FULL_GROUP_BYdinonaktifkan (perilaku asli sebelum MySQL 5.7.5) , penggunaan GROUP BYtanpa fungsi agregat dapat menghasilkan hasil yang tidak terduga, karena MySQL bebas untuk memilih nilai APAPUN dalam kumpulan data yang dikelompokkan [sic] .

Berarti suatu IDatau lastnamenilai dapat diambil yang tidak terkait dengan firstnamebaris yang diambil .


PERINGATAN

Dengan MySQL GROUP BYmungkin tidak menghasilkan hasil yang diharapkan saat digunakan bersamaORDER BY

Lihat Contoh Test Case

Metode implementasi terbaik, untuk memastikan hasil yang diharapkan, adalah dengan memfilter lingkup pengaturan hasil menggunakan subquery yang dipesan.

data table_name

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

Pertanyaan

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

Hasil

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

Perbandingan

Untuk menunjukkan hasil yang tidak terduga saat menggunakan GROUP BYdalam kombinasi denganORDER BY

Pertanyaan

SELECT * FROM table_name GROUP BY FirstName ORDER BY ID DESC

Hasil

| ID | first |  last |
|----|-------|-------|
|  2 |  Bugs | Bunny |
|  1 |  John |   Doe |
fyrye
sumber
3
Jawaban paling lengkap sejauh ini. Mengubah 'ID desc' menjadi 'ID asc' di permintaan pertama memungkinkan kami untuk mengambil 'John Doe' atau 'John Johnson'. Mengubah 'ID desc' di kueri kedua tidak memiliki efek ini.
carla
Pada postgres Anda memerlukan ID dalam grup dengan tidak yakin dengan mysql.
Sachin Prasad
Akankah GROUP BY kolom-A ORDER BY kolom-B dalam satu pernyataan SELECT selalu berfungsi dengan benar dengan versi terbaru dari MyriaDB?
Neal Davis
@NealDavis Sesuai manual MariaDBOrdering is done after grouping. , jadi Tidak tidak dalam kasus penggunaan ini, selain itu MariaDB mengabaikan ORDER BY dalam subqueries (sesuai standar SQL) tanpa a LIMIT. Anda akan ingin menggunakan Window FunctionUntuk klarifikasi lebih Anda harus menanyakan pertanyaan Anda di stackexchange DBA , karena ini adalah pertanyaan yang berhubungan dengan MySQL
fyrye
1
@NateS Tidak, GROUP BYdapat memilih nilai apa pun dalam kumpulan data yang dikelompokkan, kecuali fungsi agregat digunakan pada kolom tersebut untuk memaksa nilai tertentu. Jadi lastnameatau idbisa datang dari salah satu baris yang dipesan. Contoh subquery asli dapat diterima secara default di MySQL <= 5.7.4tetapi secara teknis masih menderita masalah. Meskipun ORDER BYtidak membantu untuk mencegah pemilihan acak, itu masih mungkin secara teoritis, tetapi dengan probabilitas jauh lebih kecil daripada tanpa menggunakan ORDER BYsubquery.
fyrye
23
SELECT ID,LastName 
From TABLE_NAME 
GROUP BY FirstName 
HAVING COUNT(*) >=1
sarath
sumber
2
menambahkan HAVINGmembuat permintaan saya 50% lebih lambat.
Buttle Butkus
Apakah ada kasus di mana HAVING COUNT (*)> = 1 akan salah?
Angelos Makrygiorgos
3
SELECT firstName, ID, LastName from tableName GROUP BY firstName
Nanhe Kumar
sumber
3

Bagaimana tentang

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

Tidak yakin apakah Anda dapat melakukan ini dengan MySQL, tetapi Anda dapat menggunakan CTE di T-SQL

; 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

Kalau tidak, Anda mungkin harus menggunakan tabel sementara.

Thomas Langston
sumber
1

Seperti yang ditunjukkan oleh fyrye , jawaban yang diterima berkaitan dengan versi MySQL yang lebih lama yang ONLY_FULL_GROUP_BYbelum diperkenalkan. Dengan MySQL 8.0.17 (digunakan dalam contoh ini), kecuali jika Anda menonaktifkan ONLY_FULL_GROUP_BYAnda akan mendapatkan pesan kesalahan berikut:

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

GALAT 1055 (42000): Ekspresi # 1 dari daftar SELECT tidak dalam klausa GROUP BY dan berisi kolom nonaggregated 'mydatabase.table_name.id' yang tidak secara fungsional bergantung pada kolom dalam GROUP BY klausa; ini tidak kompatibel dengan sql_mode = only_full_group_by

Salah satu cara untuk mengatasi ini tidak disebutkan oleh fyrye , tetapi dijelaskan dalam https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html , adalah menerapkan ANY_VALUE()fungsi ke kolom yang tidak ada dalam GROUP BYklausa ( iddan lastNamedalam contoh ini):

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)

Seperti yang tertulis dalam dokumen tersebut di atas,

Dalam hal ini, MySQL mengabaikan nondeterminisme nilai alamat dalam setiap grup nama dan menerima kueri. Ini mungkin berguna jika Anda tidak peduli nilai kolom nonagregasi mana yang dipilih untuk setiap grup. ANY_VALUE()bukan fungsi agregat, tidak seperti fungsi seperti SUM()atau COUNT(). Itu hanya bertindak untuk menekan tes untuk nondeterminisme.

Kurt Peek
sumber
Untuk klarifikasi, saya secara khusus menghindari menyarankan untuk digunakan ANY_VALUE()karena jawaban dan komentar saya difokuskan untuk mencegah hasil-hasil yang ambigu dan tidak dapat diprediksi. Karena seperti nama fungsi menyarankan, itu bisa menghasilkan nilai dari baris yang dipilih diambil. Saya sarankan menggunakan MAXatau MINsebagai gantinya.
fyrye
0

Perlu diingat ketika menggunakan grup berdasarkan dan dipesan dengan itu MySQL adalah database HANYA yang memungkinkan kolom untuk digunakan dalam grup oleh dan / atau urutan demi bagian yang bukan bagian dari pernyataan pilih.

Jadi misalnya: pilih kolom1 dari grup tabel dengan urutan kolom2 oleh kolom3

Itu tidak akan terbang di database lain seperti Postgres, Oracle, MSSQL, dll. Anda harus melakukan yang berikut dalam database tersebut

pilih kolom1, kolom2, kolom3 dari grup tabel dengan urutan kolom2 oleh kolom3

Hanya beberapa info jika Anda pernah memigrasi kode Anda saat ini ke database lain atau mulai bekerja di database lain dan mencoba untuk menggunakan kembali kode.

Antonio Delacruz
sumber
-2

Anda dapat menggunakan grup dengan untuk menampilkan nilai yang berbeda dan juga bidang yang sesuai.

select * from tabel_name group by FirstName

Sekarang Anda mendapatkan output seperti ini:

ID    FirstName     LastName
2     Bugs          Bunny
1     John          Doe


Jika Anda ingin menjawab suka

ID    FirstName     LastName
1     John          Doe
2     Bugs          Bunny

lalu gunakan kueri ini,

select * from table_name group by FirstName order by ID
John
sumber
2
Ini tidak akan selalu menghasilkan hasil yang diharapkan ketika dikelompokkan dengan pesanan oleh
fyrye
-3
SELECT DISTINCT(firstName), ID, LastName from tableName GROUP BY firstName

Akan menjadi IMO taruhan terbaik

Monty
sumber
32
ini tidak akan berhasil, itu juga akan mengambil ID dan nama belakang ke dalam evaluasi yang berbeda.
Ludo - Off the record
2
ini sama dengan DISTINCT (firstName, ID, LastName)
Tom Taylor
-4
SELECT DISTINCT (column1), column2
FROM table1
GROUP BY column1
mack
sumber
1
DISTINCT()bukan fungsi. Juga berbeda dan GROUP BY melakukan hal yang sama, jadi tidak ada alasan untuk menempatkan keduanya.
Marki555
Ini bukan pernyataan yang efisien, Anda harus menggunakan DISTINCT atau Group By tidak keduanya.
heshanlk