Yalnızca bir sütun için DISTINCT


156

Diyelim ki aşağıdaki sorgum var.

SELECT ID, Email, ProductName, ProductModel FROM Products

Yinelenen E-postaları döndürmeyecek şekilde nasıl değiştirebilirim?

Başka bir deyişle, birkaç satır aynı e-postayı içerdiğinde, sonuçların bu satırlardan yalnızca birini (tercihen sonuncusu) içermesini istiyorum. Diğer sütunlardaki kopyalara izin verilmelidir.

Cümleler tüm satırlarda çalışır DISTINCTve GROUP BYçalışır gibi görünür. Bu yüzden buna nasıl yaklaşacağımdan emin değilim.


2
Tamam, PARTITION veya iki select deyimi mi kullanmanız gerekiyor?
CarneyCode

Aynı E-postaya ancak farklı ÜrünAdına sahip 2 satır varsa ne gösterilmelidir? (Tercihen sonuncusu) açık değildir. En son hangi sipariş ile?
ypercubeᵀᴹ

@ypercube Soruda belirtildiği gibi, tercihen sonuncusu. Ancak, bu benim için gerçekten kritik değil. Sadece birini istiyorum.
Jonathan Wood

1
Şu sorulara bakabilirsiniz: soru1 , soru2 veya soru3 .
Marian

Neden kullanamıyorsunuz: SELECT DISTINCT Ürünlerden E-posta, Kimlik, Ürün Adı, ProductModel?
Rick Henderson

Yanıtlar:


186

SQL Server 2005 veya üstünü kullanıyorsanız, bunu kullanın:

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
              ) a
WHERE rn = 1

EDIT: where yan tümcesi kullanan örnek:

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
                   WHERE ProductModel = 2
                     AND ProductName LIKE 'CYBER%'

              ) a
WHERE rn = 1

4
Bu PARTITION yantümcesini araştırmalıyım, daha önce hiç çalışmadı. Örnek için teşekkürler
LorenVS

@Cybernate Bir komplikasyon: İçimin SELECTbir WHEREşartı var. Satır numaralarının tablodaki tüm satırlara atanacağını düşünüyorum. Bu sözdizimi benden biraz daha fazla. Bir satırı, WHEREkoşulu karşılayan belirli bir e-posta ile garanti edecek bir güncelleme şansı var mı?
Jonathan Wood

1
İç sql'a nereye yan tümce ekleyebilirsiniz. Dizüstü bilgisayarıma erişebildiğimde mesajı güncelleyeceğim
Chandu

1
Yazı, where yan tümcesini kullanan bir örnekle güncellendi.
Chandu

1
Bu sadece benim sorgu hiçbir JOIN s olduğunda doğru çalışıyorum . En kısa zamanda bir var olarak JOIN, ROW_NUMBERdöner "1" çok daha yüksek değerler.
Uwe Keim

10

Bu, SQL Server 2005+ ve "son" tanımınızın belirli bir e-posta için maksimum PK olduğunu varsayar.

WITH CTE AS
(
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel, 
       ROW_NUMBER() OVER (PARTITION BY Email ORDER BY ID DESC) AS RowNumber 
FROM   Products
)
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel
FROM CTE 
WHERE RowNumber = 1

6

Bunu kullandığınızda DISTINCT, sütun değil, ayrı bir satır olarak düşünün. Yalnızca sütunların tam olarak aynı olmadığı satırları döndürür.

SELECT DISTINCT ID, Email, ProductName, ProductModel
FROM Products

----------------------
1 | something@something.com | ProductName1 | ProductModel1
2 | something@something.com | ProductName1 | ProductModel1

IDSütun farklı olduğundan sorgu her iki satırı da döndürür . Ben sütun son artan dönmek istiyorsanız, o zaman böyle bir şey tavsiye: artan IDbir IDENTITYsütun olduğunu varsayalım:

SELECT DISTINCT TOP 1 ID, Email, ProductName, ProductModel
FROM Products
ORDER BY ID DESC

TOP 1Bunu sıralayarak, sadece ilk kayıt dönecektir IDilk son satırın sonuçları dönecektir azalan. Bu size son kaydı verecektir.


2
Soruda belirtildiği gibi, DISTINCT'in tüm satırda çalıştığını görüyorum. Yukarıda önerdiğiniz gibi yapmak istiyorum, ancak her seferinde e-posta sonuçlarda çoğaltılır (sadece bir kez değil).
Jonathan Wood

Bu durumda @Cybernate cevabı ile gitmenizi tavsiye ederim. Bu tam olarak ihtiyacınız olanı yapmalı.
jon3laze

4

GROUP BY işlevini kullanarak bunu yapabilirsiniz.

SELECT ID, Email, ProductName, ProductModel FROM Products GROUP BY Email


16
Seçme listesinde 'Products.ID' sütunu, toplama işlevinde veya GROUP BY deyiminde bulunmadığından geçersiz.
palota

2
Diğer sütunlar için MAX (ID), MAX (ProductName), MAX (ProductModel) gibi bir şey kullanmadan çalışmaz
avl_sweden 9:18

2
Postgres'e, sadece örn maddesi tarafından grubunda kullanılacak sütun üzerinde toplama işlevi gerek SELECT id, max(email) AS email FROM tbl GROUP by email. SQL Server'da, SELECTyan tümcedeki ALL sütunlarının toplama işlevi içinde olması gerekir. Her geri döndüğümde bu beni ısırıyor.
Bruce Pierson

Bu asla işe yaramayacak. Kötü bir çözüm
Dan AS

1

Access için burada sunduğum SQL Select sorgusunu kullanabilirsiniz:

Örneğin şu tablonuz var:

CLIENTE || NOMBRES || POSTA

888 || T800 ARNOLD || t800.arnold@cyberdyne.com

123 || JOHN KONNOR || s.connor@skynet.com

125 || SARAH CONNOR ||s.connor@skynet.com

Ve sadece farklı postaları seçmeniz gerekiyor. Bunu şu şekilde yapabilirsiniz:

SQL SEÇİMİ:

SELECT MAX(p.CLIENTE) AS ID_CLIENTE
, (SELECT TOP 1 x.NOMBRES 
    FROM Rep_Pre_Ene_MUESTRA AS x 
    WHERE x.MAIL=p.MAIL 
     AND x.CLIENTE=(SELECT MAX(l.CLIENTE) FROM Rep_Pre_Ene_MUESTRA AS l WHERE x.MAIL=l.MAIL)) AS NOMBRE, 
p.MAIL
FROM Rep_Pre_Ene_MUESTRA AS p
GROUP BY p.MAIL;

Bunu, maksimum kimliği seçmek için kullanabilirsiniz, bu maksimum kimliğe karşılık gelen adı, bu şekilde başka bir özellik ekleyebilirsiniz. Sonunda filtreye ayrı sütunu koyarsınız ve yalnızca bu son ayrı sütuna göre gruplandırırsınız.

Bu size karşılık gelen verilerle maksimum kimliği getirir, min veya diğer işlevleri kullanabilirsiniz ve bu işlevi alt sorgulara çoğaltırsınız.

Bu seçim geri dönecektir:

CLIENTE || NOMBRES || POSTA

888 || T800 ARNOLD || t800.arnold@cyberdyne.com

125 || SARAH CONNOR ||s.connor@skynet.com

Seçtiğiniz sütunları dizine eklemeyi unutmayın ve farklı sütunun tümü büyük harf veya küçük harf olarak sayısal verilere sahip olmamalıdır, aksi takdirde çalışmaz. Bu yalnızca bir kayıtlı posta ile de çalışır. Mutlu kodlama !!!


0

Tüm satırların nedeni DISTINCTve GROUP BYçalışması, sorgunuzun tüm satırları döndürmesidir.

Anlamanıza yardımcı olmak için: Sorgunun neyi döndürmesi gerektiğini elle yazmaya çalışın ve kopyalanmamış sütunlara ne koyacağınızın belirsiz olduğunu göreceksiniz.

Diğer sütunlarda ne olduğunu umursamıyorsanız, onları döndürmeyin. Her e-posta adresi için rastgele bir satır döndürmek benim için biraz işe yaramaz görünüyor.


@JohnFix Tüm satırları döndürmek istiyorum. Sonuçlar zaten E-posta sütununda aynı değere sahip bir satır içerdiğinde satırların döndürülmesini istemiyorum.
Jonathan Wood

Peki hangisinin geri döneceğine nasıl karar vermeli? Her e-posta için rasgele bir satır döndüren bir sorgu gerçekten istiyor musunuz? Bu gerçekten çözmeye çalıştığınız sorunu yeniden düşünmeniz gerekebileceği gibi kokuyor. Neredeyse bu soruyu her sorduğumda (ve çok fazla ortaya çıkıyor) geliştiricinin bu davranış için uygulamadaki sonuçları düşünmediği ortaya çıkıyor.
JohnFx

6
Gerçekten mantığını takip etmekte zorlanıyorum. Soruda belirtildiği gibi, sonuncuyu (kimliğe göre sıralanmış) tercih ederim. Evet, iyi olacak rastgele bir satır seçtiyse. Ve evet, bunu düşündüm.
Jonathan Wood

0

Bunu dene

;With Tab AS (SELECT DISTINCT Email FROM  Products)
SELECT Email,ROW_NUMBER() OVER(ORDER BY Email ASC) AS  Id FROM Tab
ORDER BY Email ASC

-2

Bunu dene:

SELECT ID, Email, ProductName, ProductModel FROM Products WHERE ID IN (SELECT MAX(ID) FROM Products GROUP BY Email)

2
Bunu neden denemeliyiz? Bu neden son 8 yılda burada verilen diğer cevaplardan daha iyi? Sorunu çözmek için daha iyi bir yol paylaşmak istiyorsanız, neden önerdiğinizi açıklamanız gerekir.
Dharman
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.