2011-01-17 6 views
5

Ich habe die folgende Abfrage, die das tut, was ich will, aber ich vermute, dass es möglich ist, dies zu tun, ohne eine Unterabfrage:Geben Priorität eines GROUP BY in MySQL ORDER BY über ohne Unterabfrage

SELECT * 
    FROM (SELECT * 
      FROM 'versions' 
     ORDER BY 'ID' DESC) AS X 
GROUP BY 'program' 

Was ich brauche, ist es, nach Programm zu gruppieren, aber die Ergebnisse für die Objekte in Versionen mit dem höchsten Wert von "ID" zurückzugeben.

In meiner Erfahrungen aus der Vergangenheit, eine Abfrage wie diese in MySQL sollte Arbeit, aber aus irgendeinem Grund ist es nicht:

SELECT * 
    FROM 'versions' 
GROUP BY 'program' 
ORDER BY MAX('ID') DESC 

Was ich wollen, ist zu tun haben, MySQL, indem man zuerst den Auftrag tun und dann die GROUP BY, aber es besteht darauf, die GROUP BY zuerst gefolgt von der ORDER BY. h., es werden die Ergebnisse der Gruppierung sortiert, anstatt die Ergebnisse der Ordnung zu gruppieren.

Natürlich ist es nicht möglich

SELECT * FROM 'versions' ORDER BY 'ID' DESC GROUP BY 'program'

Dank zu schreiben.

+0

ORDER BY hat keinen Wert vor einer Gruppe ausgeführt werden, wenn BY –

+0

vielleicht kann dieser Link helfen Ihnen - http://stackoverflow.com/questions/3695502/first-order-by-then-group-by – Alpesh

+0

Check sogar diese Verbindung. Genau das wollen Sie - http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html – Alpesh

Antwort

2

Dies sollte es tun und funktionieren ziemlich gut, solange es einen zusammengesetzten Index auf (Programm, ID) gibt. Die Unterabfrage sollte nur die erste ID für jeden Programmzweig prüfen und den erforderlichen Datensatz schnell von der äußeren Abfrage abrufen.

select v.* 
from 
(
    select program, MAX(id) id 
    from versions 
    group by program 
) m 
inner join versions v on m.program=v.program and m.id=v.id 
+0

Obwohl "id" normalerweise ein "PRIMARY KEY" ist, ist es möglich, dass dies in diesem Fall nicht der Fall ist, und es kann Dubletten auf "id" geben. Mehrere Datensätze pro "Programm" können dann zurückgegeben werden. – Quassnoi

+0

@Quassnoi - Ich verstehe das, aber wie unterscheidet sich das von dem, was Sie vorgeschlagen haben? Ich bevorzuge eine portable Abfrage. Ich konnte auch den Wert in der Unterabfrage "DISTINCT-Programm" nicht sehen, aber ich könnte etwas vermissen. – RichardTheKiwi

+0

@cyberwiki: Ich schaue wieder darauf, ich sehe, dass es nicht, da meine Abfrage darauf beruht, dass "id" eindeutig ist auch. Meine Bemerkung wäre sinnvoll, wenn der @op auf einer anderen Spalte bestellen würde. Mit einem Index sind "DISTINCT" und "GROUP BY" für den losen Scan optimiert, so dass diese Abfragen im Grunde gleich sind. +1 – Quassnoi

2
SELECT v.* 
FROM (
     SELECT DISTINCT program 
     FROM versions 
     ) vd 
JOIN versions v 
ON  v.id = 
     (
     SELECT vi.id 
     FROM versions vi 
     WHERE vi.program = vd.program 
     ORDER BY 
       vi.program DESC, vi.id DESC 
     LIMIT 1 
     ) 

Erstellen Sie einen Index auf (program, id) für diese schnell zu arbeiten.

In Bezug auf Ihre ursprüngliche Abfrage:

SELECT * FROM 'versions' GROUP BY 'program' ORDER BY MAX('ID') DESC 

Diese Abfrage in jedem SQL Dialekt außer MySQL nicht analysieren würde.

Es missbraucht MySQL die Fähigkeit, ungruppierte und nicht aggregierte Ausdrücke aus einer GROUP BY-Anweisung zurückzugeben.

+0

Ist das nicht schwerer als meine aktuelle Abfrage? Es hat zwei Unterabfragen, die beide die DB treffen müssen, während die eine, die ich gerade verwende, eine aus einer DB hat und dann die Ergebnisse dieser temporären Tabelle im Speicher abgefragt werden. –

+0

für deine Bearbeitung: Ja, welche geht mir gut. Es ist eine Inhouse-Webapp und wird nichts außer MySQL verwenden. Aber selbst dann funktioniert es nicht. Oh, und es funktioniert in SQLite. –

+0

@ ComputerGuru: Ihre aktuelle Abfrage ist falsch, so dass es egal ist, ob es heaver oder leichter ist. Solange Sie einen Index für "Programm, ID" haben, ist die Abfrage effizient: Es wird ein loser Index-Scan verwendet, um 'DISTINCT' zu machen, und ein einzelner Index sucht innerhalb jeder Gruppe nach' ORDER BY/LIMIT 1' . Die Liste "DISTINCT" ist weniger umfangreich als das vollständige Recordset. – Quassnoi

2

Per Definition wird ORDER BY verarbeitet nach Gruppierung mit GROUP BY. Per Definition ist die konzeptionelle Art und Weise jeder SELECT-Anweisung verarbeitet ist:

  1. Berechne das kartesische Produkt aller in dem FROM-Klausel referenzierten Tabellen
  2. Nehmen der Kriterien aus dem Join FROM-Klausel die Ergebnisse zu filtern
  3. Nehmen die Filterkriterien in der WHERE-Klausel, um die Ergebnisse weiter zu filtern
  4. Gruppieren Sie die Ergebnisse in Teilmengen basierend auf der GROUP BY-Klausel, kollabieren Sie die Ergebnisse für jede Teilmenge in eine einzelne Zeile und berechnen Sie die Werte aller Aggregatfunktionen - SUM(), MAX(), AVG(), usw. - für jede solche Teilmenge. Beachten Sie, dass wenn keine GROUP BY-Klausel angegeben wird, die Ergebnisse so behandelt werden, als ob es eine einzelne Teilmenge gibt und alle Aggregatfunktionen für die gesamte Ergebnismenge gelten und diese in eine einzelne Zeile zusammenfassen.
  5. Filtern Sie die jetzt gruppierten Ergebnisse basierend auf der HAVING-Klausel.
  6. Sortieren Sie die Ergebnisse anhand der ORDER BY-Klausel.

Die einzigen in den Ergebnissen erlaubt Spalten einer SELECT mit einer Klausel GROUP BY gesetzt sind, natürlich

  • Die Spalten in der Klausel GROUP BY
  • Aggregatfunktionen (wie MAX() referenzierten)
  • Literal/Konstanten
  • Ausdrücke, die von einem der obigen abgeleitet sind.

Nur gebrochene SQL-Implementierungen ermöglichen Dinge wie select xxx,yyy,a,b,c FROM foo GROUP BY xxx,yyy — den Referenzen a bis colulmsn, b und c sind bedeutungslos/undefiniert, da die einzelnen Gruppen zu einer einzigen Zeile zusammengebrochen wurden,

+0

Ich stimme dem "gebrochenen" Teil nicht zu. Es gibt seltene Fälle, wo "undefined" ein gewolltes Verhalten ist, wie "zufällig". –

+0

Es ist gebrochenes Verhalten in Bezug auf ISO 9075. –

+0

Dieses Verhalten wurde hinzugefügt, um Joins mit 'GROUP BY' zu vereinfachen, wenn eine der Tabellen auf einer' PRIMARY KEY' verbunden ist, wie folgt: 'SELECT a. *, SUM (b .value) VON einem JOIN b ON ba = a.id GROUP BY a.id'. Normalerweise müssten Sie alle Felder von "a" in "GROUP BY" einfügen, obwohl alle Werte von "a" innerhalb der Gruppe garantiert identisch sind. – Quassnoi