sql >> Database >  >> RDS >> Mysql

Hoe ORDER BY te gebruiken binnen UNION

Iets als dit zou in MySQL moeten werken:

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

om rijen te retourneren in een volgorde waarin we ze willen retourneren. d.w.z. MySQL lijkt de ORDER BY te respecteren clausules in de inline-weergaven.

Maar zonder een ORDER BY clausule op de buitenste query, is de volgorde waarin de rijen worden geretourneerd niet gegarandeerd.

Als we de rijen nodig hebben die in een bepaalde volgorde moeten worden geretourneerd, kunnen we een ORDER BY . opnemen op de buitenste vraag. In veel gevallen kunnen we gewoon een ORDER BY . gebruiken op de buitenste zoekopdracht om aan de resultaten te voldoen.

Maar als we een use-case hebben waarbij we alle rijen van de eerste query moeten retourneren vóór alle rijen van de tweede query, is een optie om een ​​extra discriminatorkolom in elk van de query's op te nemen. Voeg bijvoorbeeld ,'a' AS src . toe in de eerste zoekopdracht, ,'b' AS src naar de tweede vraag.

Dan kan de buitenste zoekopdracht ORDER BY src, name . bevatten , om de volgorde van de resultaten te garanderen.

VERVOLG

In uw oorspronkelijke zoekopdracht, de ORDER BY in uw zoekopdrachten wordt weggegooid door de optimizer; aangezien er geen ORDER BY . is toegepast op de buitenste query, is MySQL vrij om de rijen te retourneren in elke gewenste volgorde.

De "truc" in de zoekopdracht in mijn antwoord (hierboven) is afhankelijk van gedrag dat specifiek kan zijn voor sommige versies van MySQL.

Testgeval:

tabellen vullen

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

vraag

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

resultatenset geretourneerd

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

De rijen van foo2 worden "in volgorde" geretourneerd, gevolgd door de rijen van foo3 , nogmaals, "in volgorde".

Merk (opnieuw) op dat dit gedrag NIET is gegarandeerd. (Het gedrag dat we observeren is een neveneffect van hoe MySQL inline views (afgeleide tabellen) verwerkt. Dit gedrag kan anders zijn in versies na 5.5.)

Als u de rijen in een bepaalde volgorde wilt retourneren, specificeert u een ORDER BY clausule voor de buitenste query. En die volgorde is van toepassing op de gehele resultatenset.

Zoals ik eerder al zei, als ik eerst de rijen van de eerste query nodig had, gevolgd door de tweede query, zou ik in elke query een "discriminator"-kolom opnemen en vervolgens de kolom "discriminator" in de ORDER BY-clausule opnemen. Ik zou ook de inline-weergaven afschaffen en zoiets als dit doen:

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. Primaire sleutel verwijderen in MySQL

  2. Express js req.body retourneert leeg

  3. MySQL-query:UNION gebruiken en rijnummer ophalen als onderdeel van SELECT

  4. ORA-28000:het account is vergrendeld, fout wordt vaak weergegeven