Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como usar ORDER BY dentro de UNION


Algo assim deve funcionar no MySQL:
SELECT a.*
  FROM ( 
         SELECT ...  FROM ... ORDER BY ... 
       ) a
 UNION ALL 
SELECT b.*
  FROM ( 
         SELECT ...  FROM ... ORDER BY ... 
       ) b

para retornar linhas em uma ordem que gostaríamos que fossem retornadas. ou seja, o MySQL parece honrar o ORDER BY cláusulas dentro das visualizações embutidas.

Mas, sem um ORDER BY cláusula na consulta mais externa, a ordem em que as linhas são retornadas é não garantido.

Se precisarmos das linhas retornadas em uma sequência específica, podemos incluir um ORDER BY na consulta mais externa. Em muitos casos de uso, podemos usar apenas um ORDER BY na consulta mais externa para satisfazer os resultados.

Mas quando temos um caso de uso em que precisamos de todas as linhas da primeira consulta retornadas antes de todas as linhas da segunda consulta, uma opção é incluir uma coluna discriminadora extra em cada uma das consultas. Por exemplo, adicione ,'a' AS src na primeira consulta, ,'b' AS src para a segunda consulta.

Em seguida, a consulta mais externa pode incluir ORDER BY src, name , para garantir a sequência dos resultados.

ACOMPANHAMENTO

Em sua consulta original, o ORDER BY em suas consultas é descartado pelo otimizador; já que não há ORDER BY aplicado à consulta externa, o MySQL é livre para retornar as linhas na ordem que desejar.

O "truque" na consulta na minha resposta (acima) depende do comportamento que pode ser específico de algumas versões do MySQL.

Caso de teste:

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

inquerir
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

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

As linhas de foo2 são retornados "em ordem", seguidos pelas linhas de foo3 , novamente, "em ordem".

Observe (novamente) que esse comportamento NÃO garantido. (O comportamento que observamos é um efeito colateral de como o MySQL processa visualizações inline (tabelas derivadas). Esse comportamento pode ser diferente em versões posteriores à 5.5.)

Se você precisar das linhas retornadas em uma ordem específica, especifique um ORDER BY cláusula para a consulta mais externa. E essa ordenação se aplicará a toda conjunto de resultados.

Como mencionei anteriormente, se eu precisasse primeiro das linhas da primeira consulta, seguida da segunda consulta, incluiria uma coluna "discriminador" em cada consulta e, em seguida, incluiria a coluna "discriminador" na cláusula ORDER BY. Eu também acabaria com as visualizações inline e faria algo assim:
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