sql >> Database teknologi >  >> RDS >> Mysql

Sådan bruger du ORDER BY inde i UNION

Noget som dette burde virke i MySQL:

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

for at returnere rækker i en rækkefølge, som vi gerne vil have dem returneret. dvs. MySQL ser ud til at respektere ORDER BY klausuler inde i de indbyggede visninger.

Men uden en ORDER BY klausul på den yderste forespørgsel, rækkefølgen som rækkerne returneres er ikke garanteret.

Hvis vi har brug for, at rækkerne returneres i en bestemt rækkefølge, kan vi inkludere en ORDER BY på den yderste forespørgsel. I mange tilfælde kan vi bare bruge en ORDER BY på den yderste forespørgsel for at tilfredsstille resultaterne.

Men når vi har et use case, hvor vi skal have alle rækkerne fra den første forespørgsel returneret før alle rækkerne fra den anden forespørgsel, er en mulighed at inkludere en ekstra diskriminatorkolonne i hver af forespørgslerne. Tilføj f.eks. ,'a' AS src i den første forespørgsel, ,'b' AS src til den anden forespørgsel.

Så kunne den yderste forespørgsel omfatte ORDER BY src, name , for at garantere rækkefølgen af ​​resultaterne.

OPFØLGNING

I din oprindelige forespørgsel er ORDER BY i dine forespørgsler kasseres af optimeringsværktøjet; da der ikke er nogen ORDER BY anvendt på den ydre forespørgsel, kan MySQL frit returnere rækkerne i den rækkefølge, den ønsker.

"Tricket" i mit svar (ovenfor) afhænger af adfærd, der kan være specifik for nogle versioner af MySQL.

Testtilfælde:

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

forespørgsel

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

resultatsæt returneret

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

Rækkerne fra foo2 returneres "i rækkefølge", efterfulgt af rækkerne fra foo3 , igen, "i rækkefølge".

Bemærk (igen), at denne adfærd IKKE er garanteret. (Den adfærd, vi observerer, er en bivirkning af, hvordan MySQL behandler inline-visninger (afledte tabeller). Denne adfærd kan være anderledes i versioner efter 5.5.)

Hvis du har brug for, at rækkerne returneres i en bestemt rækkefølge, skal du angive en ORDER BY klausul for den yderste forespørgsel. Og den bestilling vil gælde for hele resultater.

Som jeg nævnte tidligere, hvis jeg havde brug for rækkerne fra den første forespørgsel først, efterfulgt af den anden forespørgsel, ville jeg inkludere en "diskriminator"-kolonne i hver forespørgsel og derefter inkludere "diskriminator"-kolonnen i ORDER BY-sætningen. Jeg ville også gøre op med de inline-visninger og gøre sådan noget:

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. Gendannelse af SQL Server-masterdatabasen

  2. Ukendt kolonne i 'feltliste', men kolonne findes

  3. 2 måder at oprette en tabel på, hvis den ikke allerede findes i Oracle

  4. Problem med SQLiteOpenHelper på Android 2.X og 3.X