DISTINCT ve ORDER BY aynı SELECT deyiminde nasıl kullanılır?


117

Aşağıdaki ifadeyi yürüttükten sonra:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

Veritabanından aşağıdaki değerleri alıyorum:

test3
test3
bildung
test4
test3
test2
test1

ancak yinelenenlerin şu şekilde kaldırılmasını istiyorum:

bildung
test4
test3
test2
test1

DISTINCT kullanmayı denedim ama ORDER BY ile tek bir ifadede çalışmıyor. Lütfen yardım et.

Önemli:

  1. Şununla denedim:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    çalışmıyor.

  2. CreationDate ile Sipariş çok önemlidir.


1
Nasıl çalışmıyor? Yanlış çıktı mı?
Fedearne

Yanıtlar:


195

Sorun kullanılan sütunlar olmasıdır ORDER BYbelirtilmeyen DISTINCT. Bunu yapmak için, sıralama yapmak için bir toplama işlevi kullanmanız GROUP BYve DISTINCTişi yapmak için a kullanmanız gerekir .

Bunun gibi bir şey dene:

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

99
Kategoriye göre gruplama yapıyorsanız DISTINCT anahtar kelimesine bile ihtiyacınız yoktur.
MatBailie

18

Genişletilmiş sıralama anahtarı sütunları

Yapmak istediğiniz şeyin işe yaramamasının nedeni, ilk sorgunuz için (basitleştirilmiş) olan SQL'deki mantıksal işlem sırası yüzündendir :

  • FROM MonitoringJob
  • SELECT Category, CreationDateyani, sözde bir genişletilmiş sıralama anahtarı sütunu ekleyin
  • ORDER BY CreationDate DESC
  • SELECT Categoryyani sonuçtan genişletilmiş sıralama anahtarı sütununu tekrar kaldırın .

Dolayısıyla, SQL standart genişletilmiş sıralama anahtarı sütun özelliği sayesinde, SELECTcümlecikte olmayan bir şeye göre sıralama yapmak tamamen mümkündür , çünkü geçici olarak sahne arkasına eklenmektedir.

Peki bu neden işe yaramıyor DISTINCT?

DISTINCTİşlemi eklersek, SELECTve arasına eklenecektir ORDER BY:

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

Ama şimdi, genişletilmiş sıralama anahtarı sütunu CreationDate ile DISTINCTişlemin anlamı değiştirildi, dolayısıyla sonuç artık aynı olmayacak. İstediğimiz bu değil, dolayısıyla hem SQL standardı hem de tüm makul veritabanları bu kullanımı yasaklıyor.

Geçici Çözümler

Aşağıdaki gibi standart sözdizimi ile öykünebilir

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

Veya sadece (bu durumda), Prutswonder tarafından da gösterildiği gibi

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

Burada SQL DISTINCT ve ORDER BY hakkında daha detaylı blog yazdım .


1
Bence nasıl DISTINCT ONçalıştığı konusunda yanılıyorsunuz ve burada yardımcı olmadığından oldukça eminim. Parantez içindeki ifade, farklılığı (gruplama koşulu) belirlemek için kullanılan şeydir. Aynı olan farklı kategoriler varsa CreationDate, sonuçta bunlardan sadece biri görünecektir! Belki bir şekilde yanılmış mıyım diye merak ettiğim için, iki kez kontrol etmek için blog gönderinize örnek veritabanını da yükledim: DISTINCT ONorada verdiğiniz sorgu toplam 1000 sonuç üretti (çok sayıda yinelenen lengths) ve aşağıdaki sorgu verdi yalnızca 140 (benzersiz) değer.
Inkling

@Inkling: Zaman ayırdığınız için teşekkürler. OP açıkça "kopyaların" kaldırılmasını istiyor. OP'nin ifadesine bakın "ancak kopyaların bunun gibi kaldırılmasını istiyorum" . Blog yazımdan sorguları kopyalarken muhtemelen bir hata yaptınız. Biri DISTINCT(hayır ON) kullanan ve diğeri kullanan iki sorgu vardır DISTINCT ON. Lütfen, ikincisinin açıkça yinelenen uzunlukları kaldırmadığını, ancak başlıkları yinelediğini unutmayın. Buradaki cevabımın tamamen doğru olduğunu düşünüyorum.
Lukas Eder

1
Demek istediğim, DISTINCT ONkoşullarınızın yanlış koşul kullanarak kopyaları kaldırmasıdır. Blog gönderinizdeki DISTINCT ONsorgu gerçekten de yinelenen başlıkları kaldırır , ancak üstündeki DISTINCTsorgu ve altındaki sorgu (bunun "sözdizimi şekeri" olduğunu iddia ettiğiniz) her ikisi de yinelenen uzunlukları kaldırır , çünkü muhtemelen tüm hedef budur. Aynı şey burada da geçerlidir: OP , sorguda olduğu gibi yinelenen Oluşturma Tarihlerini değil, yinelenen Kategorilerin kaldırılmasını ister . Hala bana inanmıyorsanız, kendiniz için test edin. DISTINCT ON
Inkling

6

MAX (CreationDate) çıktısı istenmiyorsa - orijinal soru örneğinde olduğu gibi - tek cevap Prashant Gupta'nın cevabının ikinci ifadesidir:

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

Açıklama: ORDER BY yan tümcesini bir satır içi işlevde kullanamazsınız, bu nedenle Prutswonder'ın yanıtındaki ifade bu durumda kullanılamaz, etrafına bir dış seçim koyup MAX (CreationDate) bölümünü atamazsınız.


2

[Category] ve [CreationDate] sütunlarının değerlerini istiyorsanız bu kodu kullanın

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

Veya sadece [Kategori] sütununun değerlerini istiyorsanız bu kodu kullanın.

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

İstediğiniz tüm farklı kayıtlara sahip olacaksınız.


bu kaşlı ayraçlar [] tamamen kafa karıştırıcı ... bu geçerli SQL sözdizimi mi?
m13r

1
Parantezler, Sıra, olay vb. Gibi anahtar sözcüklerden kaçmak içindir; bu nedenle, tablonuzda (örneğin) adlı bir sütun Eventvarsa, SQL'in bir ayrıştırma hatası atmasını durdurmak [Event]yerine yazabilirsiniz Event.
Ben Maxfield

1

2) Oluşturma Tarihine Göre Sipariş çok önemlidir

Orijinal sonuçlar "test3" ün birden fazla sonuca sahip olduğunu gösterdi ...

Group By'deki kopyaları kaldırmak için MAX'ı her zaman kullanmaya başlamak çok kolaydır ... ve altında yatan sorunun ne olduğunu unutmak veya görmezden gelmek ...

OP, tahminen, MAX kullanmanın ona son "oluşturulan" ı verdiğini ve MIN kullanmanın ilk "oluşturulan" ı vereceğini fark etti ...


3
Bu aslında soruyu yanıtlamıyor gibi görünüyor, soruyu yanıtlamak için MAXtek başına duran bir şeyden çok , diğer yanıt verenlerin kullanımları hakkında bir yorum gibi görünüyor .
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

0

Alt sorguya göre çalışmalıdır:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);

Ummm ... Olacağını sanmıyorum. Dış seçim sıralanmaz.
Hossam El-Deen

işe yaramayacak, buradayım çünkü bu işe yaramıyor
Amirreza

-1

Distinct, kayıtları artan sırada sıralayacaktır. Azalan sırada sıralamak istiyorsanız şunu kullanın:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

Kayıtları CreationDate alanına göre sıralamak istiyorsanız, bu alanın select deyiminde olması gerekir:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC

12
Bu yürütülecektir ancak OP'nin ihtiyacı olanı vermeyecektir. OP, Kategori ve OluşturmaTarihinin farklı kombinasyonları değil, farklı Kategoriler istiyor. Bu kod, her biri farklı CreationDate değerlerine sahip aynı Kategorinin birkaç örneğini verebilir.
MatBailie

-1

CTE'yi kullanabilirsiniz:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC

-3

Sonra deneyin, ancak büyük veriler için kullanışlı değil ...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);

4
"ORDER BY yan tümcesi, TOP veya FOR XML belirtilmediği sürece görünümlerde, satır içi işlevlerde, türetilmiş tablolarda, alt sorgularda ve ortak tablo ifadelerinde geçersizdir."
TechplexEngineer

Bu, siparişte CreationDate sütununu belirtmediğiniz için çalışmaz.
Mauro Bilotti

1
@TechplexEngineer Yorumunuz yanlış. Kullanılması ORDER BYalt sorgular kesinlikle geçerlidir. Hatta birisi yanlış yorumunuza olumlu oy verdi.
Racil Hilan

Bunu deniyorum ve @TechplexEngineer ile aynı hatayı yaşıyorum. Case when ile özel bir sipariş kullanıyorum.
Ege Bayrak

-4

Bunun gibi iç sorgu kullanılarak yapılabilir

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";

-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC

2
oluşturulma tarihine göre sıralanması gerekiyor !! çok önemli
rr

O halde sıralamak istediğiniz sütunu kendiniz eklemek imkansız mı? Örneğiniz alfabetik olarak sıralanmış girdileri gösterdi. Oluşturma tarihine göre sipariş vermeniz gerekiyorsa, eklemeniz yeterlidir. Gerçekten o kadar zor değil.
Furicane

8
-1: OP bunu denedi, işe yaramadı çünkü bu imkansız ve sen OP'ye patronluk yaparken bu gerçeği görmezden geldin. Buradaki nokta, DISTINCT operatörünün aynı Kategori değerine sahip, her biri potansiyel olarak farklı oluşturma tarihlerine sahip birkaç kaydı harmanlayacağıdır. Bu nedenle DISTINCT kullanıldığında mantıksal olarak imkansızdır. Bu, gerekli mantığı DISTINCT yerine GROUP BY'a iter ve oluşturma tarihinde bir toplamaya (MAX) izin verir.
MatBailie

Aslında, OP'nin ne yaptığına daha yakından bakarsanız, ki bu kesinlikle yanlış biçimlendirilmiş SQL'dir - tek bir hata yapmadım ve verilen sonuç onun istediği sonuca karşılık gelir. -1 ile uğraşmayacağım, sadece insanları düzeltmeden önce bir dahaki sefere okuyun. Teşekkür ederim.
Furicane

8
"Gerçekten o kadar da zor değil" bile diyerek, CreationDate alanını eklemeyi doğrudan önerirsiniz. Bunu yapmak, hatalı biçimlendirilmiş SQL sonucunu verir. OP'nin patronu olmak, OP'yi ilk gönderdiği ifadeye geri götüren tavsiyelerde bulunmak ve DISTINCT ile DISTINCT'de olmayan bir alana göre sipariş vermek arasındaki çekişmeyi fark etmemek için -1 aldınız. Ek olarak, 'b' 't'den önce gelir ve' 1 ',' 4'ten önce gelir, bu nedenle OP tarafından verilen sonuçlar kategorik olarak alfabetik sıraya göre değildir. Kendi tavsiyenizi size önerebilir miyim o zaman: bir dahaki sefere (daha dikkatlice) okuyun.
MatBailie
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.