Bagaimana cara menggunakan DISTINCT dan ORDER BY dalam pernyataan SELECT yang sama?

117

Setelah menjalankan pernyataan berikut:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

Saya mendapatkan nilai berikut dari database:

test3
test3
bildung
test4
test3
test2
test1

tapi saya ingin duplikatnya dihapus, seperti ini:

bildung
test4
test3
test2
test1

Saya mencoba menggunakan DISTINCT tetapi tidak berhasil dengan ORDER BY dalam satu pernyataan. Tolong bantu.

Penting:

  1. Saya mencobanya dengan:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    itu tidak berhasil.

  2. Urutan berdasarkan CreationDate sangat penting.

rr
sumber
1
Bagaimana cara kerjanya? Output salah?
Fedearne

Jawaban:

195

Masalahnya adalah bahwa kolom yang digunakan di ORDER BYtidak ditentukan di DISTINCT. Untuk melakukan ini, Anda perlu menggunakan fungsi agregat untuk mengurutkan, dan menggunakan a GROUP BYuntuk membuatnya DISTINCTberfungsi.

Coba sesuatu seperti ini:

SELECT DISTINCT Category, MAX(CreationDate) 
FROM MonitoringJob 
GROUP BY Category 
ORDER BY MAX(CreationDate) DESC, Category
Jawaban
sumber
99
Anda bahkan tidak memerlukan kata kunci DISTINCT jika Anda mengelompokkan berdasarkan Kategori.
MatBailie
18

Kolom kunci sortir diperpanjang

Alasan mengapa apa yang ingin Anda lakukan tidak berfungsi adalah karena urutan logis operasi di SQL , yang, untuk kueri pertama Anda, adalah (disederhanakan):

  • FROM MonitoringJob
  • SELECT Category, CreationDateyaitu menambahkan kolom kunci sortir diperpanjang
  • ORDER BY CreationDate DESC
  • SELECT Categoryyaitu menghapus kolom kunci sortir diperpanjang lagi dari hasil.

Jadi, berkat fitur kolom kunci pengurutan standar SQL standar , sangat mungkin untuk memesan berdasarkan sesuatu yang tidak ada dalam SELECTklausa, karena itu untuk sementara ditambahkan di belakang layar.

Jadi, mengapa ini tidak berhasil DISTINCT?

Jika kita menambahkan DISTINCToperasi, itu akan ditambahkan antara SELECTdan ORDER BY:

  • FROM MonitoringJob
  • SELECT Category, CreationDate
  • DISTINCT
  • ORDER BY CreationDate DESC
  • SELECT Category

Tapi sekarang, dengan kolom kunci sortir diperpanjang CreationDate , semantik DISTINCToperasi telah diubah, sehingga hasilnya tidak akan sama lagi. Ini bukan yang kami inginkan, jadi standar SQL, dan semua database yang masuk akal melarang penggunaan ini.

Solusi

Ini dapat diemulasikan dengan sintaks standar sebagai berikut

SELECT Category
FROM (
  SELECT Category, MAX(CreationDate) AS CreationDate
  FROM MonitoringJob
  GROUP BY Category
) t
ORDER BY CreationDate DESC

Atau, sederhananya (dalam kasus ini), seperti yang ditunjukkan juga oleh Prutswonder

SELECT Category, MAX(CreationDate) AS CreationDate
FROM MonitoringJob
GROUP BY Category
ORDER BY CreationDate DESC

Saya telah membuat blog tentang SQL DISTINCT dan ORDER BY lebih detail di sini .

Lukas Eder
sumber
1
Saya pikir Anda salah dengan cara DISTINCT ONkerjanya dan cukup yakin itu tidak membantu di sini. Ekspresi dalam tanda kurung inilah yang digunakan untuk menentukan perbedaan (kondisi pengelompokan). Jika ada kategori berbeda dengan yang sama CreationDatemaka hanya satu dari mereka yang akan muncul di hasil! Karena saya bertanya-tanya apakah mungkin saya salah, saya juga memuat contoh database di posting blog Anda untuk memeriksa ulang: DISTINCT ONkueri yang Anda berikan di sana menghasilkan total 1000 hasil (dengan banyak duplikat length) sedangkan kueri di bawahnya memberikan hanya 140 nilai (unik).
Inkling
@Inkling: Terima kasih atas waktu Anda. OP secara eksplisit ingin "duplikat" dihapus. Lihat kata-kata OP "tapi saya ingin duplikatnya dihapus, seperti ini" . Anda mungkin melakukan kesalahan saat menyalin kueri dari postingan blog saya. Ada dua kueri, satu yang menggunakan DISTINCT(tidak ON) dan satu lagi yang menggunakan DISTINCT ON. Harap perhatikan bahwa yang terakhir secara eksplisit tidak menghapus panjang duplikat, tetapi judul duplikat. Saya pikir jawaban saya di sini sepenuhnya benar.
Lukas Eder
1
Maksud saya adalah bahwa DISTINCT ONkondisi Anda menghapus duplikat menggunakan kondisi yang salah. Dalam posting blog Anda, DISTINCT ONkueri benar-benar menghapus judul duplikat , namun DISTINCTkueri di atasnya dan kueri di bawahnya (yang Anda klaim sebagai "gula sintaks" untuk) sama-sama menghapus panjang duplikat , karena mungkin itulah keseluruhan tujuan. Hal yang sama berlaku di sini: OP menginginkan Kategori duplikat dihapus, bukan duplikat Tanggal Pembuatan seperti yang dilakukan DISTINCT ONkueri. Jika Anda masih tidak mempercayai saya, uji sendiri.
Inkling
6

Jika keluaran MAX (CreationDate) tidak diinginkan - seperti pada contoh pertanyaan awal - satu-satunya jawaban adalah pernyataan kedua dari jawaban Prashant Gupta:

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

Penjelasan: Anda tidak dapat menggunakan klausa ORDER BY dalam fungsi sebaris, sehingga pernyataan dalam jawaban Prutswonder tidak dapat digunakan dalam kasus ini, Anda tidak dapat meletakkan pilihan luar di sekitarnya dan membuang bagian MAX (Tanggal Pembuatan).

Marc_Sei
sumber
2

Cukup gunakan kode ini, Jika Anda menginginkan nilai kolom [Category] dan [CreationDate]

SELECT [Category], MAX([CreationDate]) FROM [MonitoringJob] 
             GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

Atau gunakan kode ini, Jika Anda hanya menginginkan nilai kolom [Kategori].

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

Anda akan memiliki semua rekaman berbeda apa pun yang Anda inginkan.

Prashant Gupta
sumber
tanda kurung [] itu benar-benar membingungkan ... apakah ini sintaks SQL yang valid?
m13r
1
Tanda kurung adalah untuk meng-escape kata kunci, seperti Order, event, dll. Jadi jika Anda memiliki (misalnya) kolom dalam tabel EventAnda yang disebut, Anda dapat menulis [Event]alih-alih Eventmenghentikan SQL yang membuat kesalahan parse.
Ben Maxfield
1

2) Urutan berdasarkan CreationDate sangat penting

Hasil asli menunjukkan bahwa "test3" memiliki banyak hasil ...

Sangat mudah untuk mulai menggunakan MAX setiap saat untuk menghapus duplikat di Group By's ... dan melupakan atau mengabaikan pertanyaan yang mendasarinya ...

OP mungkin menyadari bahwa menggunakan MAX memberinya "ciptaan" terakhir dan menggunakan MIN akan memberikan "ciptaan" pertama ...

JohnSurrey
sumber
3
Ini tampaknya tidak benar-benar menjawab pertanyaan, ini tampaknya merupakan komentar tentang penggunaan penjawab lain MAX, daripada sesuatu yang berdiri sendiri sebagai jawaban atas pertanyaan.
DaveyDaveDave
0
if object_id ('tempdb..#tempreport') is not null
begin  
drop table #tempreport
end 
create table #tempreport (
Category  nvarchar(510),
CreationDate smallint )
insert into #tempreport 
select distinct Category from MonitoringJob (nolock) 
select * from #tempreport  ORDER BY CreationDate DESC
Bob
sumber
0

Dengan subquery, itu harus bekerja:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);
Shiwangini
sumber
Ummm ... Kurasa tidak. Pilihan luar tidak diurutkan.
Hossam El-Deen
itu tidak akan berhasil, saya di sini karena ini tidak berfungsi
Amirreza
-1

Distinct akan mengurutkan record dalam urutan menaik. Jika Anda ingin mengurutkan secara desc gunakan:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

Jika Anda ingin mengurutkan record berdasarkan field CreationDate maka field ini harus ada dalam pernyataan pilih:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC
C Patel
sumber
12
Ini akan dijalankan tetapi tidak akan memberikan apa yang dibutuhkan OP. OP menginginkan Kategori yang berbeda, bukan kombinasi Kategori dan Tanggal Buat yang berbeda. Kode ini dapat menghasilkan beberapa contoh dari Kategori yang sama, masing-masing dengan nilai CreationDate berbeda.
MatBailie
-1

Anda dapat menggunakan CTE:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC
Jair
sumber
-3

Coba selanjutnya, tetapi tidak berguna untuk data besar ...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);
Máťa - Stitod.cz
sumber
4
"Klausa ORDER BY tidak valid dalam tampilan, fungsi sebaris, tabel turunan, subkueri, dan ekspresi tabel umum, kecuali jika TOP atau FOR XML juga ditentukan."
TechplexEngineer
Ini tidak berfungsi karena Anda tidak menentukan kolom CreationDate di urutan menurut.
Mauro Bilotti
1
@TechplexEngineer Komentar Anda salah. Penggunaan ORDER BYdi sub-kueri benar-benar valid. Dan seseorang bahkan memilih komentar salah Anda.
Racil Hilan
Saya mencoba ini dan mengalami kesalahan yang sama dengan @TechplexEngineer. Saya menggunakan pesanan khusus dengan case when.
Ege Bayrak
-4

Itu bisa dilakukan dengan menggunakan permintaan batin Seperti ini

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";
Zaheer Babar
sumber
-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC
Furicane
sumber
2
saya membutuhkannya diurutkan berdasarkan tanggal pembuatan !! itu sangat penting
rr
Jadi, apakah tidak mungkin untuk menambahkan kolom yang ingin Anda pesan sendiri? Contoh Anda menunjukkan entri yang diurutkan menurut abjad. Jika Anda perlu memesan berdasarkan tanggal dibuat, tambahkan saja. Sebenarnya tidak terlalu sulit.
Furicane
8
-1: OP mencobanya, tidak berhasil, karena tidak mungkin dan Anda tampaknya mengabaikan fakta itu saat menggurui OP. Intinya adalah operator DISTINCT akan menyusun beberapa rekaman dengan nilai Kategori yang sama, masing-masing dengan tanggal pembuatan yang berpotensi berbeda. Jadi secara logis tidak mungkin saat menggunakan DISTINCT. Ini mendorong logika yang diperlukan ke GROUP BY alih-alih DISTINCT, memungkinkan agregat (MAX) pada tanggal pembuatan.
MatBailie
Sebenarnya, jika Anda melihat lebih dekat pada apa yang dilakukan OP, yang benar-benar salah format SQL - Saya tidak membuat satu kesalahan pun dan hasil yang diberikan sesuai dengan yang dia minta. Saya tidak mau -1, baca saja lain kali sebelum mengoreksi orang. Terima kasih.
Furicane
8
Anda secara langsung menyarankan untuk menambahkan bidang CreationDate, bahkan mengatakan "sebenarnya tidak terlalu sulit". Melakukannya akan menghasilkan SQL yang salah format. Anda mendapat -1 untuk menggurui OP, memberikan saran yang membawa OP kembali ke pernyataan yang awalnya dia posting, dan gagal untuk memperhatikan perselisihan antara DISTINCT dan pemesanan oleh bidang bukan dalam DISTINCT. Selain itu, 'b' muncul sebelum 't', dan '1' muncul sebelum '4', sehingga hasil yang diberikan oleh OP secara kategoris tidak sesuai dengan urutan abjad. Izinkan saya menyarankan saran Anda sendiri: baca (lebih hati-hati) lain kali.
MatBailie