Kenapa SELECT DISTINCT * FROM tabletidak bekerja untukmu?
ypercubeᵀᴹ
19
Jika tabel Anda memiliki PK, semua baris harus distinctdengan definisi. Jika Anda mencoba untuk hanya memilih DISTINCT field1tetapi entah bagaimana mengembalikan semua kolom lain apa yang harus terjadi untuk kolom-kolom yang memiliki lebih dari satu nilai untuk field1nilai tertentu ? Anda perlu menggunakan GROUP BYdan semacam agregasi di kolom lain misalnya.
Martin Smith
1
Jika Anda ingin baris berulang dan bukan hanya baris yang berbeda, hapus kata kunci yang berbeda.
Hyperboreus
2
Bisakah Anda memberikan contoh seperti apa hasil yang Anda harapkan? Sejauh ini, saya tidak dapat memahami permintaan yang Anda inginkan.
Yang terkadang dapat ditulis dengan pernyataan berbeda:
selectdistincton field1 *fromtable
Pada sebagian besar platform, tidak satu pun di atas akan berfungsi karena perilaku di kolom lain tidak ditentukan. (Yang pertama berfungsi di MySQL, jika itu yang Anda gunakan.)
Anda bisa mengambil bidang yang berbeda dan tetap memilih satu baris sewenang-wenang setiap kali.
Pada beberapa platform (misalnya PostgreSQL, Oracle, T-SQL) ini dapat dilakukan secara langsung menggunakan fungsi jendela:
Pada yang lain (MySQL, SQLite), Anda harus menulis subqueries yang akan membuat Anda bergabung dengan seluruh tabel dengan sendirinya ( contoh ), jadi tidak disarankan.
Query tidak akan mengurai bagi saya dan memberikan kesalahan: The ranking function "row_number" must have an ORDER BY clause. Kita perlu menambahkan pesanan dengan klausa setelah partisi dengan bidang1. Jadi permintaan yang benar adalah 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
Terima kasih! Saya berada di masalah yang sama dan solusinya adalah GROUP BY
Joaquin Iurchuk
2
Juga di Oracle (Pengembang Oracle SQL) Anda tidak dapat menentukan select *, row_number() over (partition by field1 order by field2) as row_number from table. Anda harus secara eksplisit menggunakan nama tabel / alias dalam kueri select **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
pemilihan
1
@jarlh: Mungkin ... hari ini. Seperti yang mungkin Anda perhatikan, jawaban ini hampir 7 tahun, suatu titik waktu di mana itu tidak terjadi sejauh yang saya ingat dari belakang ketika saya aktif. Anda dapat melakukan retag dan / atau mengedit jawaban jika Anda merasa perlu.
Denis de Bernardy
2
select distinct on (field1) * from table; bekerja juga di PostgreSQL
Chilianu Bogdan
61
Dari ungkapan pertanyaan Anda, saya mengerti bahwa Anda ingin memilih nilai yang berbeda untuk bidang tertentu dan untuk setiap nilai tersebut memiliki semua nilai kolom lainnya di baris yang sama terdaftar. Sebagian besar DBMS tidak akan mengizinkan ini dengan tidak DISTINCTjuga GROUP BY, karena hasilnya tidak ditentukan.
Pikirkan seperti ini: jika Anda field1muncul lebih dari satu kali, nilai berapa yang field2akan dicantumkan (mengingat bahwa Anda memiliki nilai yang sama field1dalam dua baris tetapi dua nilai berbeda field2dalam dua baris itu).
Namun Anda dapat menggunakan fungsi agregat (secara eksplisit untuk setiap bidang yang ingin ditampilkan) dan menggunakan GROUP BYalih-alih DISTINCT:
+1 untuk solusi ini. Jadi bisa kita lakukan SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1, dan field2, 3, 4 ,,, tidak diharuskan menjadi bilangan bulat (atau digit lainnya), mereka juga bisa menjadi ladang char
menguntit
Bekerja dengan baik sampai saya terjebak di kolom boolean. Nilai kolom MIN (Dynamic) dapat dimodifikasi menjadi false walaupun itu benar .. Fungsi agregat lain yang tersedia untuk mengatasi boolean - signonsridhar 6 mnt yang lalu. Jumlah (dinamis) berubah salah menjadi 1
signonsridhar
1
Saran yang bagus, membawa saya ke solusi yang menurut saya lebih universal - lihat!
Garrett Simpson
@signonsridhar melemparkan boolean Anda ke int dan menggunakan jumlah; misalnyasum(cast(COL as int)) > 0
Drew
26
Jika saya memahami masalah Anda dengan benar, itu mirip dengan yang baru saja saya alami. Anda ingin dapat membatasi kegunaan DISTINCT untuk bidang yang ditentukan, daripada menerapkannya ke semua data.
Jika Anda menggunakan GROUP BY tanpa fungsi agregat, bidang mana pun yang Anda GROUP BY akan menjadi DISTINCT Anda.
Jika Anda mengajukan pertanyaan:
SELECT*fromtableGROUPBY field1;
Ini akan menampilkan semua hasil Anda berdasarkan satu instance dari field1.
Misalnya, jika Anda memiliki tabel dengan nama, alamat, dan kota. Satu orang memiliki beberapa alamat yang direkam, tetapi Anda hanya ingin satu alamat untuk orang tersebut, Anda dapat meminta sebagai berikut:
SELECT*FROM persons GROUPBY name;
Hasilnya adalah bahwa hanya satu instance dari nama itu akan muncul dengan alamatnya, dan yang lainnya akan dihilangkan dari tabel yang dihasilkan. Perhatian: jika arsip Anda memiliki nilai atom seperti firstName, lastName Anda ingin dikelompokkan berdasarkan keduanya.
SELECT*FROM persons GROUPBY lastName, firstName;
karena jika dua orang memiliki nama belakang yang sama dan Anda hanya mengelompokkan berdasarkan nama belakang, salah satu dari mereka akan dihilangkan dari hasilnya. Anda perlu mempertimbangkan hal-hal itu. Semoga ini membantu.
Kenapa ada Caliassaat itu bisa bekerja tanpanya? sejalanFROM dbo.TABLE AS C
Talha
2
Saya percaya ini karena saya menggunakan RedGate SQLPrompt. Cara saya mengonfigurasinya, selalu menambahkan alias - bahkan jika tidak perlu. Itu ada "berjaga-jaga"
Stormy
Ini tampak menjanjikan bagi saya tetapi masih mengembalikan semua baris, bukan bidang yang berbeda1. :(
Michael Fever
13
Itu pertanyaan yang sangat bagus. Saya sudah membaca beberapa jawaban yang bermanfaat di sini, tetapi mungkin saya dapat menambahkan penjelasan yang lebih tepat.
Mengurangi jumlah hasil kueri dengan pernyataan GROUP BY mudah selama Anda tidak meminta informasi tambahan. Mari kita asumsikan Anda mendapat 'lokasi' tabel berikut.
--country-- --city--
France Lyon
Poland Krakow
France Paris
France Marseille
Italy Milano
Sekarang kueri
SELECT country FROM locations
GROUPBY country
akan menghasilkan:
--country--
France
Poland
Italy
Namun, pertanyaan berikut
SELECT country, city FROM locations
GROUPBY country
... melempar kesalahan dalam MS SQL, karena bagaimana komputer Anda bisa tahu yang mana dari tiga kota Prancis "Lyon", "Paris" atau "Marseille" yang ingin Anda baca di lapangan di sebelah kanan "Prancis"?
Untuk memperbaiki kueri kedua, Anda harus menambahkan informasi ini. Salah satu cara untuk melakukan ini adalah dengan menggunakan fungsi MAX () atau MIN (), memilih nilai terbesar atau terkecil di antara semua kandidat. MAX () dan MIN () tidak hanya berlaku untuk nilai numerik, tetapi juga membandingkan urutan abjad dari nilai string.
SELECT country, MAX(city)FROM locations
GROUPBY country
akan menghasilkan:
--country-- --city--
France Paris
Poland Krakow
Italy Milano
atau:
SELECT country, MIN(city)FROM locations
GROUPBY country
akan menghasilkan:
--country-- --city--
France Lyon
Poland Krakow
Italy Milano
Fungsi-fungsi ini adalah solusi yang baik selama Anda baik-baik saja dengan memilih nilai Anda dari kedua ujung urutan abjad (atau numerik). Tetapi bagaimana jika ini tidak terjadi? Mari kita asumsikan bahwa Anda memerlukan nilai dengan karakteristik tertentu, misalnya dimulai dengan huruf 'M'. Sekarang segalanya menjadi rumit.
Satu-satunya solusi yang bisa saya temukan sejauh ini adalah dengan memasukkan seluruh permintaan Anda ke dalam subquery, dan membangun kolom tambahan di luarnya dengan tangan:
SELECT
countrylist.*,(SELECTTOP1 city
FROM locations
WHERE
country = countrylist.country
AND city like'M%')FROM(SELECT country FROM locations
GROUPBY country) countrylist
akan menghasilkan:
--country-- --city--
France Marseille
Poland NULL
Italy Milano
Pertanyaan bagus @aryaxt - Anda dapat mengatakan bahwa itu adalah pertanyaan yang hebat karena Anda menanyakannya 5 tahun yang lalu dan saya menemukannya hari ini mencoba menemukan jawabannya!
Saya baru saja mencoba mengedit jawaban yang diterima untuk memasukkan ini, tetapi kalau-kalau edit saya tidak membuatnya:
Jika meja Anda tidak sebesar itu, dan dengan asumsi kunci utama Anda adalah bilangan bulat yang bertambah secara otomatis, Anda bisa melakukan sesuatu seperti ini:
SELECTtable.*FROMtable--be able to take out dupes laterLEFTJOIN(SELECT field, MAX(id)as id
FROMtableGROUPBY field
)as noDupes on noDupes.id =table.id
WHERE//this will result in only the last instance being seen
noDupes.id isnotNULL
Untuk SQL Server, Anda dapat menggunakan fungsi dense_rank dan jendela tambahan untuk mendapatkan semua baris DAN kolom dengan nilai duplikat pada kolom yang ditentukan. Berikut ini sebuah contoh ...
with t as(select col1 ='a', col2 ='b', col3 ='c', other ='r1'unionallselect col1 ='c', col2 ='b', col3 ='a', other ='r2'unionallselect col1 ='a', col2 ='b', col3 ='c', other ='r3'unionallselect col1 ='a', col2 ='b', col3 ='c', other ='r4'unionallselect col1 ='c', col2 ='b', col3 ='a', other ='r5'unionallselect col1 ='a', col2 ='a', col3 ='a', other ='r6'), tdr as(select*,
total_dr_rows = count(*)over(partitionby dr)from(select*,
dr = dense_rank()over(orderby col1, col2, col3),
dr_rn = row_number()over(partitionby col1, col2, col3 orderby other)from
t
) x
)select*from tdr where total_dr_rows >1
Ini mengambil jumlah baris untuk setiap kombinasi col1, col2, dan col3 yang berbeda.
Ini berhasil bagi saya !! Perlu dicatat, jika Anda menggunakan fetch_array () maka Anda perlu memanggil setiap baris melalui label indeks daripada secara implisit memanggil nama baris. Tidak ada cukup karakter di sini untuk saya tuliskan contoh yang saya miliki: X maaf !!
Seperti disebutkan dalam jawaban yang diterima, akan berfungsi untuk sebagian besar inkarnasi SQL - hanya untuk MYSQL
Garrett Simpson
0
Menemukan ini di tempat lain di sini tetapi ini adalah solusi sederhana yang berfungsi:
WITH cte AS/* Declaring a new table named 'cte' to be a clone of your table */(SELECT*, ROW_NUMBER()OVER(PARTITIONBY id ORDERBY 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
Klausa GROUP BY harus cocok dengan bidang yang dipilih. selain itu ia akan melempar kesalahan sepertifiled2 must appear in the GROUP BY clause or be used in an aggregate function
Viuu-a
-2
Cukup sertakan semua bidang Anda dalam klausa GROUP BY.
Itu tidak akan berhasil. Anda telah memilih kolom yang berbeda di subquery tetapi klausa di mana mendapatkan semua kolom dengan nilai itu. Jadi kueri sama baiknya dengan menulis 'pilih * dari tabel' kecuali jika kolom 'bidang' adalah kolom unik yang dalam hal ini perbedaan pada kolom itu tidak diperlukan sama sekali.
Ankur-m
-3
SELECT DISTINCT FIELD1, FIELD2, FIELD3 FROM TABLE1 berfungsi jika nilai ketiga kolom unik dalam tabel.
Jika, misalnya, Anda memiliki beberapa nilai identik untuk nama depan, tetapi nama belakang dan informasi lain di kolom yang dipilih berbeda, catatan akan dimasukkan dalam hasil yang ditetapkan.
SELECT DISTINCT * FROM table
tidak bekerja untukmu?distinct
dengan definisi. Jika Anda mencoba untuk hanya memilihDISTINCT field1
tetapi entah bagaimana mengembalikan semua kolom lain apa yang harus terjadi untuk kolom-kolom yang memiliki lebih dari satu nilai untukfield1
nilai tertentu ? Anda perlu menggunakanGROUP BY
dan semacam agregasi di kolom lain misalnya.Jawaban:
Anda mencari grup dengan:
Yang terkadang dapat ditulis dengan pernyataan berbeda:
Pada sebagian besar platform, tidak satu pun di atas akan berfungsi karena perilaku di kolom lain tidak ditentukan. (Yang pertama berfungsi di MySQL, jika itu yang Anda gunakan.)
Anda bisa mengambil bidang yang berbeda dan tetap memilih satu baris sewenang-wenang setiap kali.
Pada beberapa platform (misalnya PostgreSQL, Oracle, T-SQL) ini dapat dilakukan secara langsung menggunakan fungsi jendela:
Pada yang lain (MySQL, SQLite), Anda harus menulis subqueries yang akan membuat Anda bergabung dengan seluruh tabel dengan sendirinya ( contoh ), jadi tidak disarankan.
sumber
The ranking function "row_number" must have an ORDER BY clause
. Kita perlu menambahkan pesanan dengan klausa setelah partisi dengan bidang1. Jadi permintaan yang benar adalahselect * from ( select *, row_number() over (partition by field1 order by orderbyFieldName) as row_number from table ) as rows where row_number = 1
GROUP BY
select *, row_number() over (partition by field1 order by field2) as row_number from table
. Anda harus secara eksplisit menggunakan nama tabel / alias dalam kueriselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
select distinct on (field1) * from table
; bekerja juga di PostgreSQLDari ungkapan pertanyaan Anda, saya mengerti bahwa Anda ingin memilih nilai yang berbeda untuk bidang tertentu dan untuk setiap nilai tersebut memiliki semua nilai kolom lainnya di baris yang sama terdaftar. Sebagian besar DBMS tidak akan mengizinkan ini dengan tidak
DISTINCT
jugaGROUP BY
, karena hasilnya tidak ditentukan.Pikirkan seperti ini: jika Anda
field1
muncul lebih dari satu kali, nilai berapa yangfield2
akan dicantumkan (mengingat bahwa Anda memiliki nilai yang samafield1
dalam dua baris tetapi dua nilai berbedafield2
dalam dua baris itu).Namun Anda dapat menggunakan fungsi agregat (secara eksplisit untuk setiap bidang yang ingin ditampilkan) dan menggunakan
GROUP BY
alih-alihDISTINCT
:sumber
SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1
, dan field2, 3, 4 ,,, tidak diharuskan menjadi bilangan bulat (atau digit lainnya), mereka juga bisa menjadi ladang charsum(cast(COL as int)) > 0
Jika saya memahami masalah Anda dengan benar, itu mirip dengan yang baru saja saya alami. Anda ingin dapat membatasi kegunaan DISTINCT untuk bidang yang ditentukan, daripada menerapkannya ke semua data.
Jika Anda menggunakan GROUP BY tanpa fungsi agregat, bidang mana pun yang Anda GROUP BY akan menjadi DISTINCT Anda.
Jika Anda mengajukan pertanyaan:
Ini akan menampilkan semua hasil Anda berdasarkan satu instance dari field1.
Misalnya, jika Anda memiliki tabel dengan nama, alamat, dan kota. Satu orang memiliki beberapa alamat yang direkam, tetapi Anda hanya ingin satu alamat untuk orang tersebut, Anda dapat meminta sebagai berikut:
Hasilnya adalah bahwa hanya satu instance dari nama itu akan muncul dengan alamatnya, dan yang lainnya akan dihilangkan dari tabel yang dihasilkan. Perhatian: jika arsip Anda memiliki nilai atom seperti firstName, lastName Anda ingin dikelompokkan berdasarkan keduanya.
karena jika dua orang memiliki nama belakang yang sama dan Anda hanya mengelompokkan berdasarkan nama belakang, salah satu dari mereka akan dihilangkan dari hasilnya. Anda perlu mempertimbangkan hal-hal itu. Semoga ini membantu.
sumber
sumber
C
alias
saat itu bisa bekerja tanpanya? sejalanFROM dbo.TABLE AS C
Itu pertanyaan yang sangat bagus. Saya sudah membaca beberapa jawaban yang bermanfaat di sini, tetapi mungkin saya dapat menambahkan penjelasan yang lebih tepat.
Mengurangi jumlah hasil kueri dengan pernyataan GROUP BY mudah selama Anda tidak meminta informasi tambahan. Mari kita asumsikan Anda mendapat 'lokasi' tabel berikut.
Sekarang kueri
akan menghasilkan:
Namun, pertanyaan berikut
... melempar kesalahan dalam MS SQL, karena bagaimana komputer Anda bisa tahu yang mana dari tiga kota Prancis "Lyon", "Paris" atau "Marseille" yang ingin Anda baca di lapangan di sebelah kanan "Prancis"?
Untuk memperbaiki kueri kedua, Anda harus menambahkan informasi ini. Salah satu cara untuk melakukan ini adalah dengan menggunakan fungsi MAX () atau MIN (), memilih nilai terbesar atau terkecil di antara semua kandidat. MAX () dan MIN () tidak hanya berlaku untuk nilai numerik, tetapi juga membandingkan urutan abjad dari nilai string.
akan menghasilkan:
atau:
akan menghasilkan:
Fungsi-fungsi ini adalah solusi yang baik selama Anda baik-baik saja dengan memilih nilai Anda dari kedua ujung urutan abjad (atau numerik). Tetapi bagaimana jika ini tidak terjadi? Mari kita asumsikan bahwa Anda memerlukan nilai dengan karakteristik tertentu, misalnya dimulai dengan huruf 'M'. Sekarang segalanya menjadi rumit.
Satu-satunya solusi yang bisa saya temukan sejauh ini adalah dengan memasukkan seluruh permintaan Anda ke dalam subquery, dan membangun kolom tambahan di luarnya dengan tangan:
akan menghasilkan:
sumber
Pertanyaan bagus @aryaxt - Anda dapat mengatakan bahwa itu adalah pertanyaan yang hebat karena Anda menanyakannya 5 tahun yang lalu dan saya menemukannya hari ini mencoba menemukan jawabannya!
Saya baru saja mencoba mengedit jawaban yang diterima untuk memasukkan ini, tetapi kalau-kalau edit saya tidak membuatnya:
Jika meja Anda tidak sebesar itu, dan dengan asumsi kunci utama Anda adalah bilangan bulat yang bertambah secara otomatis, Anda bisa melakukan sesuatu seperti ini:
sumber
Mencoba
sumber
Anda bisa melakukannya dengan
WITH
klausa.Sebagai contoh:
Ini juga memungkinkan Anda untuk memilih hanya baris yang dipilih dalam
WITH
permintaan klausa.sumber
Untuk SQL Server, Anda dapat menggunakan fungsi dense_rank dan jendela tambahan untuk mendapatkan semua baris DAN kolom dengan nilai duplikat pada kolom yang ditentukan. Berikut ini sebuah contoh ...
Ini mengambil jumlah baris untuk setiap kombinasi col1, col2, dan col3 yang berbeda.
sumber
sumber
di
ORDER BY
saya baru saja memberikan contoh di sini, Anda juga dapat menambahkan bidang ID di inisumber
Menemukan ini di tempat lain di sini tetapi ini adalah solusi sederhana yang berfungsi:
sumber
Tambahkan GROUP BY ke bidang yang ingin Anda periksa duplikatnya
field1 akan diperiksa untuk mengecualikan catatan duplikat
atau Anda dapat meminta like
rekaman duplikat field1 dikecualikan dari SELECT
sumber
filed2 must appear in the GROUP BY clause or be used in an aggregate function
Cukup sertakan semua bidang Anda dalam klausa GROUP BY.
sumber
Itu bisa dilakukan dengan permintaan dalam
sumber
sumber
SELECT DISTINCT FIELD1, FIELD2, FIELD3 FROM TABLE1 berfungsi jika nilai ketiga kolom unik dalam tabel.
Jika, misalnya, Anda memiliki beberapa nilai identik untuk nama depan, tetapi nama belakang dan informasi lain di kolom yang dipilih berbeda, catatan akan dimasukkan dalam hasil yang ditetapkan.
sumber
Saya sarankan menggunakan
dengan cara ini jika Anda memiliki nilai yang sama di field1 di beberapa baris, semua catatan akan dikembalikan.
sumber
SELECT * FROM table;
. Bahkan lebih lambat.