sql >> Databasteknik >  >> RDS >> Mysql

Hur man använder ORDER BY inom UNION

Något sådant här borde fungera i MySQL:

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

för att returnera rader i en ordning som vi vill att de ska returneras. dvs MySQL verkar hedra ORDER BY satser i inline-vyerna.

Men utan en ORDER BY sats på den yttersta frågan, ordningen som raderna returneras är inte garanterat.

Om vi ​​behöver raderna returnerade i en viss sekvens kan vi inkludera en ORDER BY på den yttersta frågan. I många användningsfall kan vi bara använda en ORDER BY på den yttersta frågan för att tillfredsställa resultaten.

Men när vi har ett användningsfall där vi behöver alla rader från den första frågan returnerade före alla rader från den andra frågan, är ett alternativ att inkludera en extra diskriminatorkolumn i var och en av frågorna. Till exempel, lägg till ,'a' AS src i den första frågan, ,'b' AS src till den andra frågan.

Då kan den yttersta frågan inkludera ORDER BY src, name , för att garantera sekvensen av resultaten.

UPPFÖLJNING

I din ursprungliga fråga, ORDER BY i dina frågor kasseras av optimeraren; eftersom det inte finns någon ORDER BY tillämpas på den yttre frågan, är MySQL fri att returnera raderna i vilken ordning den vill.

"Knepet" i frågan i mitt svar (ovan) är beroende av beteende som kan vara specifikt för vissa versioner av MySQL.

Testfall:

fylla i tabeller

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');

fråga

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

resultatuppsättningen returnerades

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

Raderna från foo2 returneras "i ordning", följt av raderna från foo3 , återigen, "i ordning".

Observera (igen) att detta beteende INTE är garanterat. (Beteendet vi observerar är en bieffekt av hur MySQL bearbetar inline-vyer (härledda tabeller). Detta beteende kan vara annorlunda i versioner efter 5.5.)

Om du vill att raderna ska returneras i en viss ordning, anger du en ORDER BY klausul för den yttersta frågan. Och den beställningen kommer att gälla för hela resultat.

Som jag nämnde tidigare, om jag behövde raderna från den första frågan först, följt av den andra frågan, skulle jag inkludera en "diskriminator"-kolumn i varje fråga och sedan inkludera "diskriminator"-kolumnen i ORDER BY-satsen. Jag skulle också avskaffa de inbyggda vyerna och göra något så här:

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


  1. Skillnaden mellan mysql och mysqli

  2. PHP, ORM, MSSQL och Unicode, är det möjligt att få dessa att fungera tillsammans?

  3. SQL-fråga för att extrahera alla WordPress-inlägg med kategorier

  4. MySQL-replikering och GTID-baserad failover - en djupdykning i felaktiga transaktioner