Jak używać DISTINCT i ORDER BY w tej samej instrukcji SELECT?

117

Po wykonaniu poniższej instrukcji:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

Otrzymuję z bazy danych następujące wartości:

test3
test3
bildung
test4
test3
test2
test1

ale chcę usunąć duplikaty, na przykład:

bildung
test4
test3
test2
test1

Próbowałem użyć DISTINCT, ale nie działa z ORDER BY w jednej instrukcji. Proszę pomóż.

Ważny:

  1. Wypróbowałem to z:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    to nie działa.

  2. Kolejność według CreationDate jest bardzo ważna.

rr
źródło
1
Jak to nie działa? Niewłaściwe wyjście?
Fedearne

Odpowiedzi:

195

Problem polega na tym, że kolumny używane w ORDER BYnie są określone w DISTINCT. Aby to zrobić, musisz użyć funkcji agregującej do sortowania i użyć GROUP BYdo wykonania DISTINCTpracy.

Spróbuj czegoś takiego:

SELECT DISTINCT Category, MAX(CreationDate) 
FROM MonitoringJob 
GROUP BY Category 
ORDER BY MAX(CreationDate) DESC, Category
Prutswonder
źródło
99
Nie potrzebujesz nawet słowa kluczowego DISTINCT, jeśli grupujesz według kategorii.
MatBailie
18

Rozszerzone kolumny kluczy sortowania

Przyczyną, dla której to, co chcesz zrobić, nie działa, jest logiczna kolejność operacji w SQL , która dla twojego pierwszego zapytania jest (uproszczona):

  • FROM MonitoringJob
  • SELECT Category, CreationDatetj. dodaj tzw. rozszerzoną kolumnę klucza sortowania
  • ORDER BY CreationDate DESC
  • SELECT Categorytzn. ponownie usuń rozszerzoną kolumnę klucza sortowania z wyniku.

Tak więc, dzięki funkcji rozszerzonej kolumny klucza sortowania w standardzie SQL , jest całkowicie możliwe uporządkowanie według czegoś, czego nie ma w SELECTklauzuli, ponieważ jest do niego tymczasowo dodawane za kulisami.

Więc dlaczego to nie działa DISTINCT?

Jeśli dodamy DISTINCToperację, zostanie ona dodana między SELECTa ORDER BY:

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

Ale teraz, dzięki rozszerzonej kolumnie klucza sortowania CreationDate , semantyka DISTINCToperacji została zmieniona, więc wynik nie będzie już taki sam. Nie tego chcemy, więc zarówno standard SQL, jak i wszystkie rozsądne bazy danych zabraniają tego użycia.

Obejścia

Można go emulować za pomocą standardowej składni w następujący sposób

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

Lub po prostu (w tym przypadku), jak pokazuje również Prutswonder

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

Więcej szczegółów na temat SQL DISTINCT i ORDER BY zamieściłem tutaj .

Lukas Eder
źródło
1
Myślę, że mylisz się z tym, jak DISTINCT ONdziała i jestem pewien, że to nie pomaga tutaj. Wyrażenie w nawiasach jest używane do określenia odrębności (warunek grupowania). Jeśli istnieją różne kategorie z tym samym, CreationDatew wyniku pojawi się tylko jedna z nich! Ponieważ zastanawiałem się, czy może się w jakiś sposób nie pomyliłem, załadowałem również przykładową bazę danych w Twoim poście na blogu, aby dokładnie sprawdzić: DISTINCT ONzapytanie, które tam podałeś, dało w sumie 1000 wyników (z dużą ilością duplikatów length), podczas gdy zapytanie poniżej dało tylko 140 (unikatowych) wartości.
Inkling
@Inkling: Dziękuję za poświęcony czas. OP wyraźnie chce usunąć „duplikaty”. Zobacz sformułowanie OP „ale chcę usunąć duplikaty, w ten sposób” . Prawdopodobnie popełniłeś błąd podczas kopiowania zapytań z mojego wpisu na blogu. Istnieją dwa zapytania, jedno używające DISTINCT(nie ON) i jedno, które używa DISTINCT ON. Proszę zauważyć, że ta ostatnia wyraźnie nie usuwa zduplikowanych długości, ale zduplikowane tytuły. Myślę, że moja odpowiedź tutaj jest całkowicie poprawna.
Lukas Eder
1
Chodzi mi o to, że twoje DISTINCT ONwarunki usuwają duplikaty przy użyciu niewłaściwego warunku. W Twoim poście na blogu DISTINCT ONzapytanie rzeczywiście usuwa zduplikowane tytuły , jednak DISTINCTzapytanie nad nim i zapytanie pod nim (dla którego twierdzisz, że jest to „cukier składniowy”) usuwa zduplikowane długości , ponieważ przypuszczalnie jest to cały cel. To samo dotyczy tutaj: OP chce usunąć zduplikowane kategorie , a nie zduplikowane CreationDates, jak DISTINCT ONrobi to zapytanie. Jeśli nadal mi nie wierzysz, sprawdź sam.
Inkling
6

Jeśli wynik MAX (CreationDate) nie jest potrzebny - jak w przykładzie oryginalnego pytania - jedyną odpowiedzią jest drugie stwierdzenie odpowiedzi Prashanta Gupty:

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

Wyjaśnienie: nie możesz użyć klauzuli ORDER BY w funkcji wbudowanej, więc instrukcja w odpowiedzi Prutswonder nie jest użyteczna w tym przypadku, nie możesz umieścić wokół niej zewnętrznej selekcji i odrzucić części MAX (CreationDate).

Marc_Sei
źródło
2

Po prostu użyj tego kodu, jeśli chcesz wartości kolumn [Category] i [CreationDate]

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

Lub użyj tego kodu, jeśli chcesz tylko wartości z kolumny [Kategoria].

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

Będziesz mieć wszystkie wyraźne rekordy, co tylko zechcesz.

Prashant Gupta
źródło
te nawiasy klamrowe [] są całkowicie mylące ... czy to poprawna składnia SQL?
m13r
1
Nawiasy służą do ucieczki słów kluczowych, takich jak kolejność, zdarzenie itp., Więc jeśli masz (na przykład) kolumnę w tabeli o nazwie Event, możesz pisać [Event]zamiast Eventzatrzymywać SQL wyrzucający błąd analizy.
Ben Maxfield,
1

2) Kolejność według CreationDate jest bardzo ważna

Oryginalne wyniki wskazywały, że „test3” miał wiele wyników ...

Bardzo łatwo jest zacząć używać MAX przez cały czas, aby usunąć duplikaty w funkcji Group By ... i zapomnieć lub zignorować podstawowe pytanie ...

OP prawdopodobnie zdał sobie sprawę, że użycie MAX daje mu ostatnie „stworzone”, a użycie MIN da pierwsze „stworzone” ...

JohnSurrey
źródło
3
To tak naprawdę nie wydaje się odpowiadać na pytanie, wydaje się raczej komentarzem do zastosowań innych osób odpowiadających MAX, niż czymś, co jest samodzielną odpowiedzią na pytanie.
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
Pion
źródło
0

W podzapytaniu powinno działać:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);
Shiwangini
źródło
Ummm ... nie sądzę, żeby tak było. Zaznaczenie zewnętrzne nie jest sortowane.
Hossam El-Deen
to nie zadziała, jestem tutaj, ponieważ to nie działa
Amirreza
-1

Distinct posortuje rekordy w porządku rosnącym. Jeśli chcesz posortować w kolejności malejącej użyj:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

Jeśli chcesz sortować rekordy na podstawie pola CreationDate, to pole to musi znajdować się w instrukcji select:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC
C Patel
źródło
12
To się wykona, ale nie da tego, czego potrzebuje OP. OP chce odrębnych kategorii, a nie odrębnych kombinacji Category i CreateDate. Ten kod może dawać kilka wystąpień tej samej kategorii, z których każda ma inne wartości CreationDate.
MatBailie
-1

Możesz użyć CTE:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC
Jair
źródło
-3

Spróbuj dalej, ale nie jest to przydatne w przypadku dużych danych ...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);
Máťa - Stitod.cz
źródło
4
„Klauzula ORDER BY jest niepoprawna w widokach, funkcjach wbudowanych, tabelach pochodnych, podzapytaniach i typowych wyrażeniach tabel, chyba że określono również TOP lub FOR XML”.
TechplexEngineer
To nie działa, ponieważ nie określono kolumny CreationDate w zamówieniu według.
Mauro Bilotti
1
@TechplexEngineer Twój komentarz jest nieprawidłowy. Używanie ORDER BYw zapytaniach podrzędnych jest absolutnie poprawne. Ktoś nawet pozytywnie zagłosował na Twój nieprawidłowy komentarz.
Racil Hilan
Próbuję tego i mam ten sam błąd z @TechplexEngineer. Używam niestandardowego zamówienia z przypadkiem kiedy.
Ege Bayrak
-4

Można to zrobić za pomocą wewnętrznego zapytania w ten sposób

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";
Zaheer Babar
źródło
-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC
Furicane
źródło
2
Potrzebuję tego posortowane według daty utworzenia !! to bardzo ważne
rr
Czy nie można więc samodzielnie dodać kolumny, którą chcesz zamówić? Twój przykład pokazał wpisy uporządkowane alfabetycznie. Jeśli chcesz zamówić według daty utworzenia, po prostu ją dodaj. To naprawdę nie jest takie trudne.
Furicane,
8
-1: OP próbował tego, nie zadziałało, ponieważ jest to niemożliwe i najwyraźniej zignorowałeś ten fakt, gdy protekcjonalnie OP. Chodzi o to, że operator DISTINCT zestawi kilka rekordów o tej samej wartości Category, każdy z potencjalnie różnymi datami utworzenia. Dlatego jest to logicznie niemożliwe przy użyciu DISTINCT. To wypycha wymaganą logikę do GROUP BY zamiast DISTINCT, umożliwiając agregację (MAX) w dniu utworzenia.
MatBailie
Właściwie, jeśli przyjrzysz się bliżej temu, co zrobił OP, czyli całkowicie zniekształcony SQL - nie popełniłem ani jednego błędu, a podany wynik odpowiada temu, o który prosił. Nie będę zawracał sobie głowy -1, po prostu przeczytaj następnym razem, zanim poprawisz ludzi. Dziękuję Ci.
Furicane,
8
Sugerujesz bezpośrednio dodanie pola CreationDate, mówiąc nawet „to naprawdę nie jest takie trudne”. W ten sposób uzyskasz zniekształcony kod SQL. Dostałeś -1 za protekcjonalne traktowanie OP, udzielanie porad, które przenoszą OP z powrotem do oświadczenia, które pierwotnie opublikował, i nieuwzględnienie niezgodności między DISTINCT a porządkowaniem przez pole spoza DISTINCT. Dodatkowo „b” znajduje się przed „t”, a „1” przed „4”, dlatego wyniki podane przez PO nie są kategorycznie uporządkowane alfabetycznie. Czy mogę zatem zasugerować własną radę: następnym razem przeczytaj (dokładniej).
MatBailie