Wie verwende ich DISTINCT und ORDER BY in derselben SELECT-Anweisung?

115

Nach dem Ausführen der folgenden Anweisung:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

Ich erhalte die folgenden Werte aus der Datenbank:

test3
test3
bildung
test4
test3
test2
test1

aber ich möchte, dass die Duplikate wie folgt entfernt werden:

bildung
test4
test3
test2
test1

Ich habe versucht, DISTINCT zu verwenden, aber es funktioniert nicht mit ORDER BY in einer Anweisung. Bitte helfen Sie.

Wichtig:

  1. Ich habe es versucht mit:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    es funktioniert nicht

  2. Die Bestellung nach CreationDate ist sehr wichtig.

rr
quelle
1
Wie funktioniert es nicht? Falsche Ausgabe?
Fedearne

Antworten:

193

Das Problem ist, dass die in der verwendeten Spalten in der ORDER BYnicht angegeben sind DISTINCT. Dazu müssen Sie eine Aggregatfunktion verwenden, um zu sortieren, und eine verwenden GROUP BY, um die DISTINCTArbeit zu erledigen .

Versuchen Sie so etwas:

SELECT DISTINCT Category, MAX(CreationDate) 
FROM MonitoringJob 
GROUP BY Category 
ORDER BY MAX(CreationDate) DESC, Category
Prutswonder
quelle
98
Sie benötigen nicht einmal das Schlüsselwort DISTINCT, wenn Sie nach Kategorien gruppieren.
MatBailie
18

Erweiterte Sortierschlüsselspalten

Der Grund, warum das, was Sie tun möchten, nicht funktioniert, liegt in der logischen Reihenfolge der Operationen in SQL , die für Ihre erste Abfrage (vereinfacht) lautet:

  • FROM MonitoringJob
  • SELECT Category, CreationDatedh eine sogenannte erweiterte Sortierschlüsselspalte hinzufügen
  • ORDER BY CreationDate DESC
  • SELECT Categorydh entfernen Sie die erweiterte Sortierschlüsselspalte erneut aus dem Ergebnis.

Dank der erweiterten SQL-Standard- Sortierschlüsselspaltenfunktion ist es also durchaus möglich, nach etwas zu ordnen, das nicht in der SELECTKlausel enthalten ist, da es vorübergehend hinter den Kulissen hinzugefügt wird.

Warum funktioniert das nicht DISTINCT?

Wenn wir die DISTINCTOperation hinzufügen , wird sie zwischen SELECTund hinzugefügt ORDER BY:

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

Mit der erweiterten Sortierschlüsselspalte CreationDate wurde nun die Semantik der DISTINCTOperation geändert, sodass das Ergebnis nicht mehr dasselbe ist. Dies ist nicht das, was wir wollen, daher verbieten sowohl der SQL-Standard als auch alle vernünftigen Datenbanken diese Verwendung.

Problemumgehungen

Es kann wie folgt mit Standard-Syntax emuliert werden

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

Oder einfach (in diesem Fall), wie auch von Prutswonder gezeigt

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

Ich habe hier ausführlicher über SQL DISTINCT und ORDER BY gebloggt .

Lukas Eder
quelle
1
Ich denke, Sie irren sich mit der Funktionsweise DISTINCT ONund sind sich ziemlich sicher, dass es hier nicht hilft. Der Ausdruck in Klammern wird verwendet, um die Unterscheidbarkeit (die Gruppierungsbedingung) zu bestimmen. Wenn es verschiedene Kategorien mit derselben gibt, CreationDatewird nur eine davon im Ergebnis angezeigt! Da ich mich gefragt habe, ob ich mich vielleicht irgendwie geirrt habe, habe ich auch die Beispieldatenbank in Ihren Blog-Beitrag geladen, um sie noch einmal zu überprüfen: Die DISTINCT ONAbfrage, die Sie dort gaben, ergab insgesamt 1000 Ergebnisse (mit vielen Duplikaten length), während die Abfrage darunter ergab nur 140 (eindeutige) Werte.
Inkling
@Inkling: Danke für deine Zeit. Das OP möchte ausdrücklich, dass "Duplikate" entfernt werden. Siehe den Wortlaut von OP "aber ich möchte, dass die Duplikate so entfernt werden" . Sie haben wahrscheinlich einen Fehler beim Kopieren der Abfragen aus meinem Blog-Beitrag gemacht. Es gibt zwei Abfragen, eine, die DISTINCT(nein ON) verwendet, und eine, die verwendet DISTINCT ON. Bitte beachten Sie, dass letztere explizit keine doppelten Längen, sondern doppelte Titel entfernt. Ich denke, dass meine Antwort hier völlig richtig ist.
Lukas Eder
1
Mein Punkt ist, dass Ihre DISTINCT ONBedingungen Duplikate mit der falschen Bedingung entfernen. In Ihrem Blog-Beitrag entfernt die DISTINCT ONAbfrage zwar doppelte Titel , jedoch entfernen die DISTINCTdarüber und die darunter liegende Abfrage (für die Sie behaupten, es sei "Syntaxzucker") doppelte Längen , da dies vermutlich das gesamte Ziel ist. Hier gilt das Gleiche: Das OP möchte, dass doppelte Kategorien entfernt werden, nicht doppelte Erstellungsdaten wie bei der DISTINCT ONAbfrage. Wenn Sie mir immer noch nicht glauben, testen Sie es selbst.
Inkling
6

Wenn die Ausgabe von MAX (CreationDate) nicht gewünscht wird - wie im Beispiel der ursprünglichen Frage -, ist die einzige Antwort die zweite Aussage von Prashant Guptas Antwort:

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

Erläuterung: Sie können die ORDER BY-Klausel nicht in einer Inline-Funktion verwenden, daher ist die Anweisung in der Antwort von Prutswonder in diesem Fall nicht verwendbar. Sie können keine äußere Auswahl darum setzen und den MAX-Teil (CreationDate) verwerfen.

Marc_Sei
quelle
2

Verwenden Sie einfach diesen Code, wenn Sie Werte für die Spalten [Kategorie] und [Erstellungsdatum] wünschen

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

Oder verwenden Sie diesen Code, wenn Sie nur Werte der Spalte [Kategorie] möchten.

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

Sie haben alle unterschiedlichen Aufzeichnungen, was immer Sie wollen.

Prashant Gupta
quelle
Diese geschweiften Klammern [] sind völlig verwirrend ... ist diese gültige SQL-Syntax?
m13r
1
Die Klammern dienen zum Escapezeichen von Schlüsselwörtern wie Reihenfolge, Ereignis usw. Wenn Sie also (zum Beispiel) eine Spalte in Ihrer Tabelle haben, die aufgerufen wird Event, können Sie schreiben, [Event]anstatt Eventzu verhindern, dass SQL einen Analysefehler auslöst.
Ben Maxfield
1

2) Die Bestellung nach CreationDate ist sehr wichtig

Die ursprünglichen Ergebnisse zeigten, dass "test3" mehrere Ergebnisse hatte ...

Es ist sehr einfach, MAX ständig zu verwenden, um Duplikate in Group By zu entfernen ... und die zugrunde liegende Frage zu vergessen oder zu ignorieren ...

Das OP erkannte vermutlich, dass die Verwendung von MAX ihm das letzte "erstellte" gab und die Verwendung von MIN das erste "erstellte" ...

John Surrey
quelle
3
Dies scheint die Frage nicht wirklich zu beantworten, es scheint eher ein Kommentar zu den Verwendungen anderer Antwortender zu sein MAXals etwas, das als Antwort auf die Frage allein steht.
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
quelle
0

Durch Unterabfrage sollte es funktionieren:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);
Shiwangini
quelle
Ähm ... ich glaube nicht. Die äußere Auswahl ist nicht sortiert.
Hossam El-Deen
es wird nicht funktionieren, ich bin hier, weil das nicht funktioniert
Amirreza
-1

Distinct sortiert Datensätze in aufsteigender Reihenfolge. Wenn Sie in absteigender Reihenfolge sortieren möchten, verwenden Sie:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

Wenn Sie Datensätze basierend auf dem Feld CreationDate sortieren möchten, muss sich dieses Feld in der select-Anweisung befinden:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC
C Patel
quelle
12
Dies wird ausgeführt, gibt aber nicht das, was das OP benötigt. Das OP möchte unterschiedliche Kategorien, keine unterschiedlichen Kombinationen von Kategorie und Erstellungsdatum. Dieser Code kann mehrere Instanzen derselben Kategorie mit jeweils unterschiedlichen CreationDate-Werten ergeben.
MatBailie
-1

Sie können CTE verwenden:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

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

Versuchen Sie es als nächstes, aber es ist nicht nützlich für große Datenmengen ...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);
Máťa - Stitod.cz
quelle
4
"Die ORDER BY-Klausel ist in Ansichten, Inline-Funktionen, abgeleiteten Tabellen, Unterabfragen und allgemeinen Tabellenausdrücken ungültig, sofern nicht auch TOP oder FOR XML angegeben ist."
TechplexEngineer
Dies funktioniert nicht, da Sie in der Bestellung von nicht die Spalte CreationDate angegeben haben.
Mauro Bilotti
1
@TechplexEngineer Dein Kommentar ist falsch. Die Verwendung ORDER BYin Unterabfragen ist absolut gültig. Und jemand hat sogar Ihren falschen Kommentar hochgestimmt.
Racil Hilan
Ich versuche dies und habe den gleichen Fehler mit @TechplexEngineer. Ich verwende eine benutzerdefinierte Bestellung mit Fall, wenn.
Ege Bayrak
-4

Dies kann mit einer inneren Abfrage wie dieser erfolgen

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";
Zaheer Babar
quelle
-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC
Furicane
quelle
2
Ich brauche es sortiert nach Erstellungsdatum! es ist sehr wichtig
rr
Ist es also unmöglich, die Spalte, die Sie bestellen möchten, selbst hinzuzufügen? Ihr Beispiel zeigte Einträge in alphabetischer Reihenfolge. Wenn Sie nach Erstellungsdatum bestellen müssen, fügen Sie es einfach hinzu. Es ist wirklich nicht so schwierig.
Furicane
8
-1: Das OP hat das versucht, es hat nicht funktioniert, weil es unmöglich ist und Sie diese Tatsache anscheinend ignoriert haben, als Sie das OP bevormundeten. Der Punkt ist, dass der DISTINCT-Operator mehrere Datensätze mit demselben Kategoriewert mit möglicherweise unterschiedlichen Erstellungsdaten zusammenstellt. Daher ist es bei Verwendung von DISTINCT logisch unmöglich. Dadurch wird die erforderliche Logik anstelle von DISTINCT auf GROUP BY verschoben, sodass am Erstellungsdatum ein Aggregat (MAX) zulässig ist.
MatBailie
Wenn Sie sich genauer ansehen, was das OP getan hat, was absolut fehlerhaftes SQL ist, habe ich keinen einzigen Fehler gemacht, und das angegebene Ergebnis entspricht dem von ihm angeforderten. Ich werde mich nicht um -1 kümmern, sondern nur das nächste Mal lesen, bevor ich Leute korrigiere. Danke dir.
Furicane
8
Sie schlagen direkt vor, das Feld "CreationDate" hinzuzufügen und sogar zu sagen, "es ist wirklich nicht so schwierig". Wenn Sie dies tun, erhalten Sie das fehlerhafte SQL. Sie haben -1 erhalten, wenn Sie das OP bevormunden, Ratschläge geben, die das OP zu der von ihm ursprünglich veröffentlichten Anweisung zurückführen, und weil Sie den Konflikt zwischen DISTINCT und der Bestellung durch ein Feld, das nicht im DISTINCT enthalten ist, nicht bemerkt haben. Zusätzlich steht 'b' vor 't' und '1' vor '4', sodass die vom OP angegebenen Ergebnisse kategorisch nicht in alphabetischer Reihenfolge sind. Darf ich dann Ihren eigenen Rat vorschlagen: Lesen Sie das nächste Mal (genauer).
MatBailie