MySQL, karşılık gelen diğer sütunlarla birlikte bir sütun DISTINCT seçin


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

Sütundan DISTINCTsonuçları seçmek istiyorum FirstName, ancak karşılık gelen IDve ihtiyacım var LastName.

Sonuç kümesinin yalnızca birini göstermesi gerekir John, ancak ID1 ve a LastNameDoe ile.


1
Farklı bir ada sahip en düşük kimliğe ait soyad mı istiyorsunuz?
Thomas Langston

3
İlkinin seçimine girmesi gereken mantık nedir? Hem John Doe hem de John Johnson'ın iki ayrı Johns oldukları için görünmesini isteyeceğinizi düşünürdüm ama bu sadece benim.
judda

4
DISTINCTbir işlev değildir. İle olan tüm cevaplar DISTINCT()yanlış. Hata, daha sonra yerleştirmediğinizde görünecektir SELECT.
Question Overflow

1
ALL Farklı sözcükten sonra parantez kullanılarak verilen yanıtlar gerçekten yanlıştır. Farklı bir işlev DEĞİLDİR, bu nedenle parametre kabul edemez. Farklı olan parantezler göz ardı edilir. Parantezlerin "karmaşık veri türü" oluşturacağı PostgreSQL kullanmadığınız sürece
Used_By_Already

Yanıtlar:


192

bu sorguyu dene

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

16
Hangi satırın döndürüleceğini nasıl bilebiliriz?
William Entriken

27
@Full Terbiyeli, MySQL belgelerine göre yapamazsınız : "Sunucu her gruptan herhangi bir değer seçmekte özgürdür, bu yüzden aynı olmadıkça seçilen değerler belirsizdir." Uygulamada ORDER BY yan tümcesiyle bu tür sorguları başarıyla kullandım, örneğin ORDER BY id ekleyebilirsiniz ASC / DESC ve MySQL, sorguyu her çalıştırdığınızda tutarlı sonuçlar döndürür. Ama kimsenin üretim ortamında belgelenmemiş özellikleri kullanması gerekip gerekmediğinden emin olabilirim.
Arunas Junevicius

2
OP mysql sürümünden bahsetmiyor.
diEcho

2
@sinaza 5.7.5+değiştirilmiş GROUP BYkullanım
fyrye

3
Ne ID ne de LastName ne toplulaştırılmış ne de gruplama işlevinin bir parçası olmadığı için, bu yalnızca only_full_group_by modu ile çalışmaz. Yardım!
ihodonald

64

DISTINCTAnahtar kelime gerçekten bunu bekliyorsanız şekilde çalışmıyor. Kullandığınızda SELECT DISTINCT col1, col2, col3aslında tüm benzersiz {col1, col2, col3} gruplarını seçersiniz.


14
Bunu gösterdiğin için teşekkürler Brian. Aynı sonuçları elde etmek için GROUP BY'ı nasıl kullanabileceğime bir örnek verebilir misiniz?
Bay

59

GROUP BYToplama işlevi olmadan kullanıldığında, kabul edilen yanıtta kullanıldığı gibi, beklenmedik sonuçlardan kaçınmak için , MySQL bir toplama işlevi [sic] ve sorunları kullanılmadığında gruplanan veri kümesindeki HERHANGİ bir değeri almakta serbesttir . Lütfen bir hariç tutma katılımı kullanmayı düşünün.ONLY_FULL_GROUP_BY

Hariç Tutma Katılımı - Belirsiz Varlıklar

Adın ve soyadının benzersiz bir şekilde dizine eklendiğini (açık) varsayarsak, alternatif olarak sonuç kümesini filtrelemek GROUP BYiçin a'yı kullanarak LEFT JOINhariç tutma JOIN olarak sıralamaktır.

Gösteriye bakın

Artan düzen (AZ)

AZ'den soyadı tarafından sıralanan ayrı adı almak için

Sorgu

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;

Sonuç

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

Azalan düzen (ZA)

ZA'dan soyadı tarafından sıralanan ayrı adı almak için

Sorgu

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;

Sonuç

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

Daha sonra, elde edilen verileri istediğiniz gibi sipariş edebilirsiniz.


Hariç Tutma Katılımı - Belirsiz Varlıklar

Ad ve soyadı birleşimi benzersiz değilse (belirsiz) ve aynı değerlere sahip birden çok satırınız varsa, kimliğe göre de filtrelemek için JOIN ölçütlerine OR koşulu ekleyerek sonuç kümesine filtre uygulayabilirsiniz.

Gösteriye bakın

tablo_adı verileri

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

Sorgu

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;

Sonuç

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

Sıralı Alt Sorgu

DÜZENLE

Sıralı bir alt sorgu kullanarak orijinal yanıtım , değişikliklerden dolayı artık geçerli olmayan MySQL 5.7.5'ten önce yazılmıştır ONLY_FULL_GROUP_BY. Lütfen bunun yerine yukarıdaki hariç tutma birleşim örneklerini kullanın.

Ayrıca not etmek önemlidir; zaman ONLY_FULL_GROUP_BYdevre dışı (MySQL 5.7.5 önce orijinal davranışı) kullanımı GROUP BYMySQL seçmek için serbest olduğu için bir toplama işlevi olmadan beklenmedik sonuçlar doğurabilir BİR gruplandırılmasına veri kümesi içindeki değeri [sic] .

Alınan satırla ilişkili olmayan bir anlam IDveya lastnamedeğer alınabilir .firstname


UYARI

MySQL GROUP BYile birlikte kullanıldığında beklenen sonuçları vermeyebilirORDER BY

Test Örneği Örneğine Bakın

Beklenen sonuçları sağlamak için en iyi uygulama yöntemi, sonuç kümesi kapsamını sıralı bir alt sorgu kullanarak filtrelemektir.

tablo_adı verileri

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

Sorgu

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

Sonuç

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

karşılaştırma

GROUP BYİle birlikte kullanırken beklenmedik sonuçları göstermek içinORDER BY

Sorgu

SELECT * FROM table_name GROUP BY FirstName ORDER BY ID DESC

Sonuç

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

3
Şimdiye kadar en eksiksiz cevap. İlk sorguda "ID desc" i "ID asc" olarak değiştirmek, "John Doe" veya "John Johnson" ı almamızı sağlar. İkinci sorguda 'ID desc' değiştirmenin bu etkisi yoktur.
carla

Postgres üzerinde mysql emin değilken grup kimliği gerekir.
Sachin Prasad

Bir SELECT deyimindeki GROUP BY sütunu-A ORDER BY sütunu-B her zaman MyriaDB'nin en son sürümüyle doğru çalışır mı?
Neal Davis

@NealDavis MariaDB kılavuzuna göre Ordering is done after grouping., bu kullanım durumunda değil, ayrıca MariaDB, alt sıralarda (SQL standardına göre) olmadan ORDER BY'ı yok sayarLIMIT . Kullanmak istersiniz Window FunctionDaha fazla açıklama için sorunuzu DBA
stackexchange'te sormalısınız

1
@NateS Hayır, GROUP BYbelirli bir değeri zorlamak için bu sütunlarda bir toplama işlevi kullanılmadığı sürece gruplandırılmış veri kümesi içindeki herhangi bir değeri seçebilir. Yani lastnameya idda sıralı herhangi bir satırdan gelebilir. Orijinal alt sorgu örneği varsayılan olarak kabul edilebilirdi MySQL <= 5.7.4ancak teknik olarak hala sorun yaşıyor. ORDER BYRastgele bir seçimi önlemeye yardımcı olsa da, yine de teorik olarak mümkündür, ancak ORDER BYalt sorguyu kullanmadan önemli ölçüde daha az olasılıkla .
fyrye



3

Peki ya

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

2

Bunu MySQL ile yapıp yapamayacağınızdan emin değilsiniz, ancak T-SQL'de bir CTE kullanabilirsiniz

; 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

Aksi takdirde geçici bir tablo kullanmanız gerekebilir.


1

Fyrye tarafından işaret edildiği gibi, kabul edilen cevap MySQL'in ONLY_FULL_GROUP_BYhenüz tanıtılmamış olan eski sürümleriyle ilgilidir . MySQL 8.0.17 ile (bu örnekte kullanılır), devre dışı bırakmazsanız ONLY_FULL_GROUP_BYaşağıdaki hata iletisini alırsınız:

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

HATA 1055 (42000): SELECT listesinin 1. ifadesi GROUP BY deyiminde değil ve GROUP BY deyimindeki sütunlara işlevsel olarak bağımlı olmayan birleştirilmiş 'mydatabase.table_name.id' sütunu içeriyor; bu sql_mode = only_full_group_by ile uyumsuz

Bu sorunu çözmek için fyrye tarafından belirtilmeyen ancak https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html dosyasında açıklanan bir yol , ANY_VALUE()işlevi aşağıdaki sütunlara uygulamaktır. GROUP BYmaddede değil ( idve lastNamebu örnekte):

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)

Yukarıda belirtilen dokümanlarda yazıldığı gibi,

Bu durumda, MySQL her ad grubundaki adres değerlerinin belirsizliğini göz ardı eder ve sorguyu kabul eder. Her grup için birleştirilmiş olmayan bir sütunun hangi değerinin seçildiğine dikkat etmezseniz bu yararlı olabilir. ANY_VALUE(), SUM()veya gibi işlevlerin aksine bir toplama işlevi değildir COUNT(). Belirsizliğin testini bastırmak için kullanılır.


Açıklamak için, ANY_VALUE()cevabım ve yorumların belirsiz ve öngörülemeyen sonuç kümelerini önlemeye odaklandığından özellikle kaçınmayı önledim. İşlev adından da anlaşılacağı gibi, seçilen satırlardan herhangi bir değerin alınmasıyla sonuçlanabilir. Bunun yerine MAXveya MINkullanmanızı öneririm .
fyrye

0

Grubu tarafından kullanırken ve bu sıraya göre sıralarken, MySQL'in, select deyiminin parçası olmayan parçalara göre ve / veya parçaya göre grupların kullanılmasına izin veren SADECE veritabanı olduğunu unutmayın.

Örneğin: tablo grubundan sütun2 sırasını sütun3'e göre sütun1'i seçin

Bu, Postgres, Oracle, MSSQL, vb. Gibi diğer veritabanlarında uçmaz. Bu veritabanlarında aşağıdakileri yapmanız gerekir

tablo grubundan sütun2 sırasına göre sütun3, sütun2, sütun3'ü seçin

Mevcut kodunuzu başka bir veritabanına geçirmeniz veya başka bir veritabanında çalışmaya başlamanız ve kodu yeniden kullanmaya çalışmanız durumunda bazı bilgiler.


-2

Farklı değerleri ve karşılık gelen alanları görüntülemek için gruplama ölçütü'nü kullanabilirsiniz.

select * from tabel_name group by FirstName

Şimdi şöyle çıktı aldınız:

ID    FirstName     LastName
2     Bugs          Bunny
1     John          Doe


Gibi cevaplamak istiyorsanız

ID    FirstName     LastName
1     John          Doe
2     Bugs          Bunny

sonra bu sorguyu kullanın,

select * from table_name group by FirstName order by ID

2
Bu,
fyrye

-3
SELECT DISTINCT(firstName), ID, LastName from tableName GROUP BY firstName

En iyi bahis IMO olur


32
bu işe yaramaz, aynı zamanda kimliği ve soyadını ayrı bir değerlendirmeye alır.
Kızma Birader - Rekor dışı

2
Bu DISTINCT (firstName, ID, LastName) ile aynıdır
Tom Taylor

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

1
DISTINCT()bir işlev değildir. Ayrıca DISTINCT ve GROUP BY aynı şeyi yapıyorlar, bu yüzden ikisini de hiçbir sebep göstermiyor.
Marki555

Bu etkili bir ifade değildir, DISTINCT veya Group By değerlerini ikisini birden kullanmamalısınız.
heshanlk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.