Pisahkan hanya satu kolom

155

Katakanlah saya memiliki pertanyaan berikut.

SELECT ID, Email, ProductName, ProductModel FROM Products

Bagaimana saya bisa memodifikasinya sehingga tidak menghasilkan Email duplikat?

Dengan kata lain, ketika beberapa baris berisi email yang sama, saya ingin hasilnya hanya menyertakan satu dari baris tersebut (lebih disukai yang terakhir). Duplikat di kolom lain harus diizinkan.

Klausa suka DISTINCTdan GROUP BYtampaknya bekerja pada seluruh baris. Jadi saya tidak yakin bagaimana cara mendekati ini.

Jonathan Wood
sumber
2
Ok, Anda perlu menggunakan PARTISI atau menggunakan dua pernyataan pilih?
CarneyCode
Dan apa yang harus ditampilkan jika ada 2 baris dengan Email yang sama tetapi ProductName berbeda? The (sebaiknya yang terakhir) tidak jelas. Terakhir dengan pemesanan yang mana?
ypercubeᵀᴹ
@ ypercube Seperti yang dinyatakan dalam pertanyaan, sebaiknya yang terakhir. Namun, itu tidak terlalu penting bagi saya. Saya hanya ingin salah satunya.
Jonathan Wood
1
Anda dapat melihat pertanyaan-pertanyaan berikut: question1 , question2 atau question3 .
Marian
Mengapa Anda tidak dapat menggunakan: SELECT DISTINCT Email, ID, ProductName, ProductModel FROM Products?
Rick Henderson

Jawaban:

186

Jika Anda menggunakan SQL Server 2005 atau lebih baru gunakan ini:

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: Contoh menggunakan klausa where:

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
Chandu
sumber
4
Saya harus menyelidiki klausa PARTISI ini, tidak pernah melihatnya dalam tindakan sebelumnya. Terima kasih untuk contohnya
LorenVS
@Cybernate One komplikasi: Batin saya SELECTmembutuhkan suatu WHEREkondisi. Saya pikir nomor baris akan diberikan ke semua baris dalam tabel. Sintaks ini hanya sedikit di luar saya. Adakah peluang pembaruan yang akan menjamin satu baris dengan email tertentu yang memenuhi WHEREpersyaratan?
Jonathan Wood
1
Anda dapat menambahkan di mana klausa ke dalam sql. Saya akan memperbarui posting setelah saya dapat mengakses laptop saya
Chandu
1
Memperbarui posting dengan sampel menggunakan klausa where.
Chandu
1
Saya mendapatkan ini berfungsi dengan benar hanya ketika tidak ada JOIN dalam permintaan saya. Segera setelah saya memiliki JOIN, nilai yang ROW_NUMBERdikembalikan jauh lebih tinggi daripada "1".
Uwe Keim
10

Ini mengasumsikan SQL Server 2005+ dan definisi Anda "terakhir" adalah maks PK untuk email yang diberikan

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
Pero P.
sumber
6

Ketika Anda menggunakan DISTINCTmenganggapnya sebagai baris yang berbeda, bukan kolom. Ini akan mengembalikan hanya baris di mana kolom tidak sama persis sama.

SELECT DISTINCT ID, Email, ProductName, ProductModel
FROM Products

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

Kueri akan mengembalikan kedua baris karena IDkolomnya berbeda. Saya berasumsi bahwa IDkolom adalah IDENTITYkolom yang bertambah, jika Anda ingin mengembalikan yang terakhir maka saya merekomendasikan sesuatu seperti ini:

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

The TOP 1akan kembali hanya catatan pertama, dengan memesan itu dengan IDturun itu akan mengembalikan hasil dengan baris terakhir pertama. Ini akan memberi Anda catatan terakhir.

jon3laze
sumber
2
Seperti yang dinyatakan dalam pertanyaan, saya melihat bahwa DISTINCT berfungsi pada seluruh baris. Saya ingin melakukan seperti yang Anda sarankan di atas, tetapi untuk setiap kali email digandakan dalam hasil (tidak hanya sekali).
Jonathan Wood
Dalam hal ini saya akan merekomendasikan pergi dengan jawaban @Cybernate. Itu harus melakukan apa yang Anda butuhkan.
jon3laze
4

Anda dapat mengatasinya dengan menggunakan fungsi GROUP BY

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

Marshall Unduemi
sumber
16
Kolom 'Products.ID' tidak valid dalam daftar pilih karena tidak terkandung dalam fungsi agregat atau klausa GROUP BY.
palota
2
Ini tidak berfungsi tanpa menggunakan sesuatu seperti MAX (ID), MAX (ProductName), MAX (ProductModel) untuk kolom lainnya
avl_sweden
2
Dalam postgres, Anda hanya perlu fungsi agregat pada kolom yang akan digunakan dalam grup dengan klausa, misalnya SELECT id, max(email) AS email FROM tbl GROUP by email. Dalam SQL Server SEMUA kolom dalam SELECTklausa harus dalam fungsi agregat. Ini menggigit saya setiap kali saya kembali.
Bruce Pierson
Ini tidak akan pernah berhasil. Ini adalah solusi yang buruk
Dan AS
1

Untuk Access, Anda dapat menggunakan kueri Select SQL yang saya sajikan di sini:

Misalnya Anda memiliki tabel ini:

CLIENTE || NOMBRES || SURAT

888 || T800 ARNOLD || [email protected]

123 || JOHN CONNOR || [email protected]

125 || SARAH CONNOR ||[email protected]

Dan Anda hanya perlu memilih email yang berbeda. Anda dapat melakukannya dengan ini:

SQL SELECT:

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;

Anda dapat menggunakan ini untuk memilih ID maksimum, nama koresponden ke ID maksimum itu, Anda dapat menambahkan atribut lain dengan cara itu. Kemudian pada akhirnya Anda meletakkan kolom berbeda untuk difilter dan Anda hanya mengelompokkannya dengan kolom berbeda terakhir.

Ini akan memberi Anda ID maksimum dengan data koresponden, Anda dapat menggunakan min atau fungsi lainnya dan Anda mereplikasi fungsi itu ke sub-kueri.

Pilih ini akan kembali:

CLIENTE || NOMBRES || SURAT

888 || T800 ARNOLD || [email protected]

125 || SARAH CONNOR ||[email protected]

Ingatlah untuk mengindeks kolom yang Anda pilih dan kolom yang berbeda harus tidak memiliki data numerik semuanya dalam huruf besar atau huruf kecil, atau tidak akan berfungsi. Ini akan bekerja dengan hanya satu surat terdaftar juga. Selamat coding !!!

jRam90
sumber
0

Alasan DISTINCTdan GROUP BYbekerja pada seluruh baris adalah permintaan Anda mengembalikan seluruh baris.

Untuk membantu Anda memahami: Cobalah untuk menulis dengan tangan apa yang harus dikembalikan oleh kueri dan Anda akan melihat bahwa tidak jelas apa yang harus dimasukkan ke dalam kolom yang tidak terduplikasi.

Jika Anda benar-benar tidak peduli dengan apa yang ada di kolom lain, jangan kembalikan. Mengembalikan baris acak untuk setiap alamat email sepertinya sedikit tidak berguna bagi saya.

JohnFx
sumber
@ JohnFix Saya ingin mengembalikan seluruh baris. Saya hanya tidak ingin baris dikembalikan ketika hasilnya sudah termasuk baris dengan nilai yang sama di kolom Email.
Jonathan Wood
Jadi bagaimana seharusnya memutuskan yang mana yang akan dikembalikan? Apakah Anda benar-benar menginginkan kueri yang mengembalikan baris arbitrer untuk setiap email. Ini benar-benar bau seperti Anda mungkin perlu memikirkan kembali masalah yang Anda coba selesaikan. Hampir setiap kali saya ditanya pertanyaan ini (dan banyak muncul) ternyata pengembang belum memikirkan konsekuensi dalam aplikasi untuk perilaku ini.
JohnFx
6
Saya benar-benar kesulitan mengikuti logika Anda. Seperti yang dinyatakan dalam pertanyaan, saya lebih suka yang terakhir (diurutkan berdasarkan ID). Ya, jika ia memilih baris acak, itu tidak masalah. Dan, ya, saya sudah memikirkannya.
Jonathan Wood
0

Coba ini

;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
Abdullah Yousuf
sumber
-2

Coba ini:

SELECT ID, Email, ProductName, ProductModel FROM Products WHERE ID IN (SELECT MAX(ID) FROM Products GROUP BY Email)
Сергей Пустовит
sumber
2
Kenapa kita harus mencoba ini? Mengapa ini lebih baik daripada jawaban lain yang diposting di sini dalam 8 tahun terakhir? Jika Anda ingin berbagi cara yang lebih baik untuk menyelesaikan masalah, Anda perlu menjelaskan mengapa Anda merekomendasikannya.
Dharman