SQL / mysql - Farklı / UNIQUE seçin ancak tüm sütunları döndürmek?


373
SELECT DISTINCT field1, field2, field3, ......   FROM table

Aşağıdaki sql deyimi gerçekleştirmek çalışıyorum ama tüm sütunları döndürmek istiyorum bu mümkün mü? Gibi bir şey:

SELECT DISTINCT field1, * from table

12
Neden SELECT DISTINCT * FROM tablesenin için çalışmıyor?
ypercubeᵀᴹ

19
Tablonuzda bir PK varsa tüm satırlar distincttanım gereği olmalıdır . Sadece seçmeye çalıştığınız DISTINCT field1halde bir şekilde diğer tüm sütunları döndürmeye çalışıyorsanız, belirli bir değer için birden fazla değeri olan sütunlar için ne olmalıdır field1? GROUP BYÖrneğin, diğer sütunlarda bir tür toplama kullanmanız gerekir .
Martin Smith

1
Yalnızca farklı satırlar değil, tekrarlanan satırlar da istiyorsanız, farklı anahtar kelimeyi kaldırın.
Hyperboreus

2
Sonuçların nasıl görünmesini beklediğinize bir örnek verebilir misiniz? Şimdiye kadar istediğiniz sorguyu anlamıyorum.
özyinelemeli

3
İşte sorulan benzer sorunun cevabı, önce kimlikleriyle ayrı bir sütun almanız ve daha sonra orijinal tabloyla birleştirmeniz gerekir. Bir sütundaki DISTINCT öğesini seçin, diğer birden çok sütunu
döndürün

Yanıtlar:


407

Şuna göre bir grup arıyorsunuz:

select *
from table
group by field1

Hangi zaman zaman farklı bir ifadeyle yazılabilir:

select distinct on field1 *
from table

Bununla birlikte, çoğu platformda, diğer sütunlardaki davranış belirtilmediğinden yukarıdakilerin hiçbiri çalışmaz. (İlk kullandığınız şey MySQL'de çalışır.)

Farklı alanları getirebilir ve her seferinde tek bir rastgele satır seçmeye devam edebilirsiniz.

Bazı platformlarda (örn. PostgreSQL, Oracle, T-SQL) bu doğrudan pencere işlevleri kullanılarak yapılabilir:

select *
from (
   select *,
          row_number() over (partition by field1 order by field2) as row_number
   from table
   ) as rows
where row_number = 1

Diğerlerinde (MySQL, SQLite), tüm tabloyu kendisiyle birleştirmenizi sağlayacak alt sorgular yazmanız gerekir ( örnek ), bu yüzden önerilmez.


10
Sorgu benim için ayrıştırmak ve bir hata verir vermez: The ranking function "row_number" must have an ORDER BY clause. Field1 tarafından bölümlendirildikten sonra yan tümce ile sipariş eklememiz gerekir. Yani doğru sorgu select * from ( select *, row_number() over (partition by field1 order by orderbyFieldName) as row_number from table ) as rows where row_number = 1
Ankur-m

1
Teşekkürler! Ben aynı sorun vardı ve çözüm oldu GROUP BY
Joaquin Iurchuk

2
Ayrıca Oracle'da (Oracle SQL Developer) belirtemezsiniz select *, row_number() over (partition by field1 order by field2) as row_number from table. Seçme sorgusunda tablo adını / diğer adını açıkça kullanmalısınızselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
meta4

1
@jarlh: Olabilir ... bugün. Gördüğünüz gibi, bu cevap neredeyse 7 yaşında, aktifken arkadan hatırlayabildiğim sürece durum böyle değildi. Gerekli olduğunu düşünüyorsanız cevabı yeniden etiketleyebilir ve / veya düzenleyebilirsiniz.
Denis de Bernardy

2
select distinct on (field1) * from table; PostgreSQL'de de çalışıyor
Chilianu Bogdan

61

Sorunuzun ifadesinden, belirli bir alan ve aynı satırdaki diğer tüm sütun değerlerinin listelenmesini sağlamak için bu değerlerin her biri için ayrı değerleri seçmek istediğinizi anlıyorum. Çoğu DBMS buna ne izin ne DISTINCTdeGROUP BY sonuç belirlenir değildir çünkü.

Bunu şöyle düşünün: eğer field1birden çok kez gerçekleşirse, hangi değerinin field2listeleneceği ( field1iki satırda aynı değere sahip olduğunuz, ancak field2bu iki satırda iki farklı değere sahip olduğunuz göz önüne alındığında ).

Bununla birlikte, toplama işlevlerini (gösterilmesini istediğiniz her alan için açık bir şekilde) ve aşağıdakilerin GROUP BYyerine kullanabilirsiniz DISTINCT:

SELECT field1, MAX(field2), COUNT(field3), SUM(field4), .... FROM table GROUP BY field1

4
Bu çözüm için +1. Böylece yapabiliriz SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1ve alan2, 3, 4 ,,, tamsayı (veya diğer rakamlar) olmak zorunda değildir, bunlar da char alanları olabilir
sap

Boole sütununda sıkışana kadar güzel çalışıyordu. MIN (Dinamik) sütun değerleri, doğru olsa bile false değerine değiştirilir. Sum (dynamic) false olarak 1 olarak değiştirildi
signonsridhar

1
Büyük öneri, beni daha evrensel olduğunu düşündüğüm çözümüme götürdü - bir göz atın!
Garrett Simpson

@signonsridhar, boolean'ınızı int ve kullanım toplamına dönüştürür; ör.sum(cast(COL as int)) > 0
Drew

26

Sorununuzu doğru anladıysam, sahip olduğum soruna benzer. DISTINCT'in kullanılabilirliğini, tüm verilere uygulamak yerine belirli bir alanla sınırlandırmak istiyorsunuz.

GROUP BY'ı bir toplama işlevi olmadan kullanırsanız, GROUP BY alanında herhangi bir alan DISTINCT dosyanız olacaktır.

Sorgunuzu yaparsanız:

SELECT * from table GROUP BY field1;

Tüm sonuçlarınızı alan 1'in tek bir örneğini temel alarak gösterecektir.

Örneğin, ad, adres ve şehir içeren bir tablonuz varsa. Tek bir kişinin kayıtlı birden fazla adresi vardır, ancak yalnızca kişi için tek bir adres istiyorsanız, aşağıdaki gibi sorgulayabilirsiniz:

SELECT * FROM persons GROUP BY name;

Sonuç, adresiyle birlikte bu adın yalnızca bir örneğinin görünmesi ve diğerinin sonuç tablosundan çıkarılmasıdır. Dikkat: dosyalarınızda firstName, lastName gibi atom değerleri varsa, her ikisine göre gruplandırmak istersiniz.

SELECT * FROM persons GROUP BY lastName, firstName;

çünkü iki kişi aynı soyadına sahipse ve yalnızca soyadına göre gruplandırırsanız, bu kişilerden biri sonuçlardan çıkarılır. Bunları göz önünde bulundurmalısınız. Bu yardımcı olur umarım.


Kabul edilen cevapta belirtildiği gibi, SQL'in enkarnasyonları için işe yarar - sadece MYSQL için
Garrett Simpson

15
SELECT  c2.field1 ,
        field2
FROM    (SELECT DISTINCT
                field1
         FROM   dbo.TABLE AS C
        ) AS c1
        JOIN dbo.TABLE AS c2 ON c1.field1 = c2.field1

C aliasOnsuz çalışabileceği zaman neden var ? içindeFROM dbo.TABLE AS C
Talha

2
Bunun RedGate SQLPrompt kullanmamdan kaynaklandığına inanıyorum. Yapılandırdığım şekilde, gereksiz olsa bile her zaman takma adlar ekler. "Her ihtimale karşı" orada
Stormy

Bu benim için ümit verici görünüyordu ama yine de farklı alanları değil tüm satırları geri getirdi1. :(
Michael Fever

13

Bu gerçekten iyi bir soru. Burada zaten bazı yararlı cevapları okudum, ama muhtemelen daha kesin bir açıklama ekleyebilirim.

Ek bilgileri sorgulamadığınız sürece sorgu sonuçlarının sayısını GROUP BY deyimiyle azaltmak kolaydır. Diyelim ki aşağıdaki tablodaki 'yerleri' var.

--country-- --city--
 France      Lyon
 Poland      Krakow
 France      Paris
 France      Marseille
 Italy       Milano

Şimdi sorgu

SELECT country FROM locations
GROUP BY country

sonuçlanacak:

--country--
 France
 Poland
 Italy

Ancak, aşağıdaki sorgu

SELECT country, city FROM locations
GROUP BY country

... MS SQL'de hata veriyor, çünkü bilgisayarınız "Fransa" nın sağındaki alanda okumak için üç Fransız şehri "Lyon", "Paris" veya "Marsilya" dan hangisini nasıl bilebilir?

İkinci sorguyu düzeltmek için bu bilgileri eklemelisiniz. Bunu yapmanın bir yolu, tüm adaylar arasında en büyük veya en küçük değeri seçerek MAX () veya MIN () işlevlerini kullanmaktır. MAX () ve MIN () yalnızca sayısal değerler için geçerli değildir, aynı zamanda dize değerlerinin alfabetik sırasını da karşılaştırır.

SELECT country, MAX(city) FROM locations
GROUP BY country

sonuçlanacak:

--country-- --city--
 France      Paris
 Poland      Krakow
 Italy       Milano

veya:

SELECT country, MIN(city) FROM locations
GROUP BY country

sonuçlanacak:

--country-- --city--
 France      Lyon
 Poland      Krakow
 Italy       Milano

Bu işlevler, alfabetik (veya sayısal) sıranın her iki ucundan değerinizi seçmenizle iyi olduğunuz sürece iyi bir çözümdür. Peki ya durum böyle değilse? Diyelim ki belirli bir karakteristik değere, örneğin 'M' harfinden başlayarak bir değere ihtiyacınız var. Şimdi işler karmaşıklaşıyor.

Şimdiye kadar bulabildiğim tek çözüm, tüm sorgunuzu bir alt sorguya koymak ve bunun dışında ek sütunu el ile oluşturmaktır:

SELECT
     countrylist.*,
     (SELECT TOP 1 city
     FROM locations
     WHERE
          country = countrylist.country
          AND city like 'M%'
     )
FROM
(SELECT country FROM locations
GROUP BY country) countrylist

sonuçlanacak:

--country-- --city--
 France      Marseille
 Poland      NULL
 Italy       Milano

5

Büyük soru @aryaxt - harika bir soru olduğunu söyleyebilirsin, çünkü 5 yıl önce sordun ve bugün cevabı bulmaya çalıştım!

Bunu dahil etmek için kabul edilen cevabı düzenlemeye çalıştım, ancak düzenlemem bunu yapmazsa:

Tablonuz o kadar büyük değilse ve birincil anahtarınızın otomatik olarak artan bir tam sayı olduğunu varsayarsak, şöyle bir şey yapabilirsiniz:

SELECT 
  table.*
FROM table
--be able to take out dupes later
LEFT JOIN (
  SELECT field, MAX(id) as id
  FROM table
  GROUP BY field
) as noDupes on noDupes.id = table.id
WHERE
  //this will result in only the last instance being seen
  noDupes.id is not NULL

5

Deneyin

SELECT table.* FROM table 
WHERE otherField = 'otherValue'
GROUP BY table.fieldWantedToBeDistinct
limit x

3

Bir ile yapabilirsiniz WITH cümle .

Örneğin:

WITH c AS (SELECT DISTINCT a, b, c FROM tableName)
SELECT * FROM tableName r, c WHERE c.rowid=r.rowid AND c.a=r.a AND c.b=r.b AND c.c=r.c

Bu ayrıca yalnızca WITHyan tümce sorgusunda seçilen satırları seçmenize olanak tanır .


2

SQL Server için, belirtilen sütunlarda yinelenen değerlere sahip tüm satırları VE sütunları almak için dense_rank ve ek pencere işlevlerini kullanabilirsiniz. İşte bir örnek...

with t as (
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r1' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r2' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r3' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r4' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r5' union all
    select col1 = 'a', col2 = 'a', col3 = 'a', other = 'r6'
), tdr as (
    select 
        *, 
        total_dr_rows = count(*) over(partition by dr)
    from (
        select 
            *, 
            dr = dense_rank() over(order by col1, col2, col3),
            dr_rn = row_number() over(partition by col1, col2, col3 order by other)
        from 
            t
    ) x
)

select * from tdr where total_dr_rows > 1

Bu, col1, col2 ve col3'ün her bir farklı kombinasyonu için bir satır sayısı alıyor.


çok karmaşık ve bir SQL uygulaması için özel
Garrett Simpson

1
select min(table.id), table.column1
from table 
group by table.column1

Bu benim için çalıştı !! Eğer fetch_array () kullanıyorsanız tho belirtmek gerekir, o zaman her satırı satır adını örtülü olarak çağırmak yerine bir dizin etiketi ile çağırmanız gerekir. İçinde bulunduğum örneği yazmam için yeterli karakter yok: X özür dilerim !!
Brandon Printiss

0
SELECT *
FROM tblname
GROUP BY duplicate_values
ORDER BY ex.VISITED_ON DESC
LIMIT 0 , 30

içinde ORDER BYben sadece burada örnek koyduk, ayrıca bu kimlik alanını ekleyebilir


Kabul edilen cevapta belirtildiği gibi, SQL'in enkarnasyonları için çalışır - sadece MYSQL için
Garrett Simpson

0

Bunu burada başka bir yerde buldum, ancak bu işe yarayan basit bir çözüm:

 WITH cte AS /* Declaring a new table named 'cte' to be a clone of your table */
 (SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY val1 DESC) AS rn
 FROM MyTable /* Selecting only unique values based on the "id" field */
 )
 SELECT * /* Here you can specify several columns to retrieve */
 FROM cte
 WHERE rn = 1

MSSQL için çalışıyor
Michael Fever

-1

Sorgunuzun benzeyebileceği kopyaları kontrol etmek istediğiniz alana GROUP BY ekleyin

SELECT field1, field2, field3, ......   FROM table GROUP BY field1

alan1, yinelenen kayıtları hariç tutmak için işaretlenecek

ya da şöyle sorgulayabilirsiniz

SELECT *  FROM table GROUP BY field1

alan1 yinelenen kayıtları SELECT dışında bırakılır


1
GROUP BY deyimi seçilen alanlarla eşleşmelidir. aksi halde hata atacakfiled2 must appear in the GROUP BY clause or be used in an aggregate function
Viuu -a

-2

Tüm alanlarınızı GROUP BY deyimine dahil etmeniz yeterlidir.


3
Bunu iyi bir cevap haline getirmek için, ne demek istediğiniz hakkında biraz daha ayrıntı eklemelisiniz.
Robbert

-2

İç sorgu ile yapılabilir

$query = "SELECT * 
            FROM (SELECT field
                FROM table
                ORDER BY id DESC) as rows               
            GROUP BY field";

2
Bu soruya cevap vermez, OP tablonun tüm verilerini almaya çalışıyordu, ancak tek bir alanın kopyalarını içeren satırları kaldırmaya çalışıyordu
Garrett Simpson

-3
SELECT * from table where field in (SELECT distinct field from table)

7
Bu işi yapmayacak. Alt sorguda ayrı bir sütun seçtiniz, ancak where yan tümcesi bu değere sahip tüm sütunları alır. Bu nedenle, sorgu 'alan' sütunu benzersiz bir sütun değilse, bu durumda o sütundakinden hiçbirine gerek duyulmadığı sürece, sorgu 'tablodan * seç' yazmak kadar iyidir.
Ankur-m

-3

TABLO1'den DISTINCT FIELD1, FIELD2, FIELD3 SEÇİN üç tablonun değerleri tabloda benzersizse çalışır.

Örneğin, ad için birden çok özdeş değeriniz varsa, ancak seçilen sütunlardaki soyadı ve diğer bilgiler farklıysa, kayıt sonuç kümesine dahil edilir.


2
Bu soruya cevap vermez, OP tablonun tüm verilerini almaya çalışıyordu, ancak tek bir alanın kopyalarını içeren satırları kaldırmaya çalışıyordu
Garrett Simpson

-3

Kullanmanızı öneririm

SELECT  * from table where field1 in 
(
  select distinct field1 from table
)

bu şekilde alan1'de birden çok satırda aynı değere sahipseniz, tüm kayıtlar döndürülür.


1
İle farklı değil SELECT * FROM table;. Dahası Yavaş.
Shin Kim

Lütfen önce cevabınızı deneyin.
Şerif
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.