Saltar al contenido

Cómo utilizar ORDER BY inside UNION

Solución:

Algo como esto debería funcionar en MySQL:

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

Sin embargo, tenga en cuenta que en ausencia ORDER BY (o GROUP BY) en la consulta más externa, el orden en que se devuelven las filas es NO garantizado.

Si necesita que las filas se devuelvan en una secuencia en particular, debe incluir un ORDER BY en la consulta más externa. En muchos casos de uso, podemos usar un ORDER BY en la consulta más externa para satisfacer los resultados.

Sin embargo, si tiene un caso de uso en el que necesita que se devuelvan todas las filas de la primera consulta antes de todas las filas de la segunda consulta, una opción es incluir una columna discriminadora adicional en cada una de las consultas. Por ejemplo, agregue ,'a' AS src en la primera consulta, ,'b' AS src a la segunda consulta.

Entonces la consulta más externa podría incluir ORDER BY src, name, para garantizar la secuencia de los resultados.


HACER UN SEGUIMIENTO

En su consulta original, el ORDER BY en sus consultas es descartado por el optimizador; ya que no hay ORDER BY aplicado a la consulta externa, MySQL es libre de devolver las filas en el orden que desee.

El “truco” en la consulta en mi respuesta (arriba) depende del comportamiento que puede ser específico de algunas versiones de MySQL.

Caso de prueba:

poblar tablas

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

consulta

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 devuelto

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

Las filas de foo2 se devuelven “en orden”, seguidos de las filas de foo3, nuevamente, “en orden”.

Tenga en cuenta (de nuevo) que este comportamiento es NO garantizado. (El comportamiento que observamos es un efecto secundario de cómo MySQL procesa las vistas en línea (tablas derivadas). Este comportamiento puede ser diferente en las versiones posteriores a la 5.5).

Si necesita que las filas se devuelvan en un orden particular, especifique un ORDER BY cláusula para la consulta más externa. Y ese orden se aplicará al completo conjunto resultante.

Como mencioné anteriormente, si primero necesitara las filas de la primera consulta, seguidas de la segunda, incluiría una columna de “discriminador” en cada consulta y luego incluiría la columna de “discriminador” en la cláusula ORDER BY. También eliminaría las vistas en línea y haría algo como esto:

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

Solo usa un ORDER BY al final.

La Unión convierte dos selecciones en una selección lógica. El orden se aplica a todo el conjunto, no a cada parte.

Tampoco use ningún parens. Solo:

SELECT 1 as Origin, blah blah FROM foo WHERE x
UNION ALL
SELECT 2 as Origin, blah blah FROM foo WHERE y
ORDER BY Origin, z

No use ORDER BY en un individuo SELECT declaración dentro de un UNION, a menos que estés usando LIMIT con eso.

Los documentos de MySQL en UNION explican por qué (el énfasis es mío):

Para aplicar ORDER BY o LIMIT a un SELECT individual, coloque la cláusula dentro del paréntesis que encierra el SELECT:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

Sin embargo, el uso de ORDER BY para instrucciones SELECT individuales no implica nada sobre el orden en el que aparecen las filas en el resultado final porque UNION de forma predeterminada produce un conjunto de filas desordenado. Por lo tanto, el uso de ORDER BY en este contexto es típicamente junto con LIMIT, por lo que se usa para determinar el subconjunto de las filas seleccionadas para recuperar para SELECT, aunque no necesariamente afecta el orden de esas filas en el resultado final de UNION. Si ORDER BY aparece sin LIMIT en un SELECT, se optimiza porque no tendrá ningún efecto de todos modos.

Para usar una cláusula ORDER BY o LIMIT para ordenar o limitar todo el resultado de UNION, entre paréntesis las declaraciones SELECT individuales y coloque ORDER BY o LIMIT después de la última. El siguiente ejemplo usa ambas cláusulas:

(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

Parece un ORDER BY cláusula como la siguiente le dará lo que desea:

ORDER BY user_id, name
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *