Mysql
 sql >> Datenbank >  >> RDS >> Mysql

So verwenden Sie ORDER BY innerhalb von UNION

So etwas sollte in MySQL funktionieren:

SELECT a.*
  FROM ( 
         SELECT ...  FROM ... ORDER BY ... 
       ) a
 UNION ALL 
SELECT b.*
  FROM ( 
         SELECT ...  FROM ... ORDER BY ... 
       ) b

um Zeilen in einer Reihenfolge zurückzugeben, die wir gerne zurückgeben möchten. d.h. MySQL scheint den ORDER BY zu berücksichtigen Klauseln innerhalb der Inline-Ansichten.

Aber ohne ORDER BY -Klausel in der äußersten Abfrage ist die Reihenfolge, in der die Zeilen zurückgegeben werden, nicht garantiert.

Wenn wir die zurückgegebenen Zeilen in einer bestimmten Reihenfolge benötigen, können wir einen ORDER BY einfügen auf der äußersten Abfrage. In vielen Anwendungsfällen können wir einfach einen ORDER BY verwenden auf der äußersten Abfrage, um die Ergebnisse zu erfüllen.

Aber wenn wir einen Anwendungsfall haben, in dem wir alle Zeilen aus der ersten Abfrage vor allen Zeilen aus der zweiten Abfrage zurückgeben müssen, besteht eine Möglichkeit darin, eine zusätzliche Diskriminatorspalte in jede der Abfragen aufzunehmen. Fügen Sie beispielsweise ,'a' AS src hinzu in der ersten Abfrage ,'b' AS src zur zweiten Abfrage.

Dann könnte die äußerste Abfrage ORDER BY src, name enthalten , um die Reihenfolge der Ergebnisse zu gewährleisten.

NACHVERFOLGUNG

In Ihrer ursprünglichen Abfrage der ORDER BY in Ihren Abfragen wird vom Optimierer verworfen; da es kein ORDER BY gibt Auf die äußere Abfrage angewendet, kann MySQL die Zeilen in beliebiger Reihenfolge zurückgeben.

Der "Trick" bei der Abfrage in meiner Antwort (oben) hängt vom Verhalten ab, das für einige Versionen von MySQL spezifisch sein kann.

Testfall:

Tabellen füllen

CREATE TABLE foo2 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;
CREATE TABLE foo3 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;

INSERT INTO foo2 (id, role) VALUES 
  (1,'sam'),(2,'frodo'),(3,'aragorn'),(4,'pippin'),(5,'gandalf');
INSERT INTO foo3 (id, role) VALUES 
  (1,'gimli'),(2,'boromir'),(3,'elron'),(4,'merry'),(5,'legolas');

Abfrage

SELECT a.*
  FROM ( SELECT s.id, s.role
           FROM foo2 s
          ORDER BY s.role
       ) a
 UNION ALL
SELECT b.*
  FROM ( SELECT t.id, t.role
           FROM foo3 t
          ORDER BY t.role
       ) b

Ergebnismenge zurückgegeben

    id  role     
 ------  ---------
      3  aragorn  
      2  frodo    
      5  gandalf  
      4  pippin   
      1  sam      
      2  boromir  
      3  elron    
      1  gimli    
      5  legolas  
      4  merry    

Die Zeilen von foo2 werden "in der Reihenfolge" zurückgegeben, gefolgt von den Zeilen von foo3 , wieder "in Ordnung".

Beachten Sie (erneut), dass dieses Verhalten NICHT ist garantiert. (Das Verhalten, das wir beobachten, ist ein Nebeneffekt davon, wie MySQL Inline-Ansichten (abgeleitete Tabellen) verarbeitet. Dieses Verhalten kann in Versionen nach 5.5 anders sein.)

Wenn Sie die Zeilen in einer bestimmten Reihenfolge zurückgeben möchten, geben Sie ORDER BY an -Klausel für die äußerste Abfrage. Und diese Reihenfolge gilt für das gesamte Ergebnismenge.

Wie ich bereits erwähnt habe, würde ich, wenn ich zuerst die Zeilen aus der ersten Abfrage benötigte, gefolgt von der zweiten Abfrage, eine "Diskriminator"-Spalte in jede Abfrage aufnehmen und dann die "Diskriminator"-Spalte in die ORDER BY-Klausel aufnehmen. Ich würde auch die Inline-Ansichten abschaffen und so etwas tun:

SELECT s.id, s.role, 's' AS src
  FROM foo2 s
 UNION ALL
SELECT t.id, t.role, 't' AS src
  FROM foo3 t
 ORDER BY src, role