Usando union y order by clause en mysql

123

Quiero usar order by con union en la consulta mysql. Estoy buscando diferentes tipos de registros basados ​​en diferentes criterios de una tabla basada en la distancia para una búsqueda en mi sitio. La primera consulta de selección devuelve datos relacionados con la búsqueda exacta del lugar. La segunda consulta de selección devuelve datos relacionados con la distancia dentro de los 5 km del lugar buscado. La tercera consulta de selección devuelve datos relacionados con la distancia dentro de 5-15 kms del lugar buscado.

Luego estoy usando union para fusionar todos los resultados y mostrarlos en una página con paginación. Bajo el encabezado apropiado como 'Resultados de búsqueda exactos' , 'Resultados dentro de 5 kms', etc.

Ahora quiero ordenar los resultados en función de id o add_date. Pero cuando agrego orden por cláusula al final de mi consulta (query1 union query 2 union query 3 ordenar por add_date). Ordena todos los resultados. Pero lo que quiero es que se clasifique debajo de cada encabezado.

Aditya
fuente
¿Qué tipo (s) es / son los campos por los que desea ordenar en cada tabla?
user151841

Respuestas:

221

Puede hacer esto agregando una pseudocolumna denominada rango a cada selección, que puede ordenar primero, antes de ordenar por sus otros criterios, por ejemplo:

select *
from (
    select 1 as Rank, id, add_date from Table 
    union all
    select 2 as Rank, id, add_date from Table where distance < 5
    union all
    select 3 as Rank, id, add_date from Table where distance between 5 and 15
) a
order by rank, id, add_date desc
RedFilter
fuente
9
¿Por qué hay ay el final?
Uday Hiwarale
25
MySQL requiere que las tablas derivadas tengan un alias.
RedFilter
44
@ RedFilter, no lo entiendo del todo. ¿Cuál es el objetivo de "seleccionar todo como una tabla derivada" cuando simplemente podemos seleccionar las 3 tablas y luego hacer una order by? ( "para ordenar o limitar el UNIONresultado completo , SELECTponer entre paréntesis las declaraciones individuales y colocar el ORDER BYo LIMITdespués del último" ). Compare su código con i.stack.imgur.com/LpTMU.png
Pacerier
1
@Pacerier Si esa sintaxis funciona con MySQL, ¡adelante! Mi sintaxis es un poco más multiplataforma, generalmente no trabajo con MySQL. Sin embargo, en realidad lo prefiero, ya que funciona en casos más generalizados, por ejemplo, considere cuándo solo desea las primeras diez coincidencias de la última consulta de UNION; creo que de todos modos tendría que recurrir a mi sintaxis.
RedFilter
1
@Pacerier, también considere que el valor de esta manera permite que la "selección *" superior sea "select id, add_date" y elimine "rank" de los resultados si no desea verlos.
Dev Null
45

Puede usar subconsultas para hacer esto:

select * from (select values1 from table1 order by orderby1) as a
union all
select * from (select values2 from table2 order by orderby2) as b
rickythefox
fuente
1
Tnx, bueno para separar las órdenes. También podemos tener una disposición diferente si la cláusula de orden era común pero queremos que los resultados se separen (en lugar de separar órdenes): SELECT * FROM ( SELECT aaa AS Col, 1 AS Official FROM table1 UNION ALL SELECT bbb AS Col, 0 AS Official FROM table2 ) AS tbl ORDER BY Official, Col
Alix
18
Esto es incorrecto : el uso de declaraciones ORDER BYindividuales SELECTno implica nada sobre el orden en que aparecen las filas en el resultado final
shmosel
Tienes razón, la respuesta aceptada es también la correcta. Esto simplemente funcionó bien cuando lo probé.
rickythefox
shmosel (y rickythefox): la unión no elimina todos los duplicados, por lo que no tiene ninguna razón para cambiar el tipo de selecciones individuales ordenadas. Es por eso que funcionó para usted en el pasado, y por qué funcionará para usted en el futuro. El orden en mal estado en el resultado final se debe a que UNION (DISTINCT) necesita algún tipo de clasificación para combinar filas de manera eficiente. O más específicamente, ordena porque combina filas de manera eficiente. Por lo tanto, puede confiar en la unión para preservar sus subconsultas.
Gerard ONeill
2
Esto funcionaba muy bien para versiones anteriores de MySQL, ahora este enfoque NO funcionará. Porque el estándar SQL no garantiza preservar el orden de las subconsultas.
Andrei
28
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 

order by add_date
Mitali
fuente
Esto funcionó, pero curiosamente necesitaba cambiar una cosa: necesitaba dar un alias compartido al campo que estaba ordenando. Trabajó además de eso, gracias!
HoldOffHunger
9

Una consulta de unión solo puede tener una ORDER BYcláusula maestra , IIRC. Para obtener esto, en cada consulta que constituya la UNIONconsulta mayor , agregue un campo que será el campo por el que clasifique para el UNION's ORDER BY.

Por ejemplo, podrías tener algo como

SELECT field1, field2, '1' AS union_sort
UNION SELECT field1, field2, '2' AS union_sort
UNION SELECT field1, field2, '3' AS union_sort
ORDER BY union_sort

Ese union_sortcampo puede ser cualquier cosa por la que desee ordenar. En este ejemplo, resulta que primero coloca los resultados de la primera tabla, la segunda tabla, etc.

usuario151841
fuente
9

No olvide que union all es una forma de agregar registros a un conjunto de registros sin ordenarlos ni fusionarlos (en oposición a union).

Así por ejemplo:

select * from (
    select col1, col2
    from table a
    <....>
    order by col3
    limit by 200
) a
union all
select * from (
    select cola, colb
    from table b
    <....>
    order by colb
    limit by 300
) b

Mantiene las consultas individuales más claras y le permite ordenar por diferentes parámetros en cada consulta. Sin embargo, al usar la forma de la respuesta seleccionada, puede ser más claro dependiendo de la complejidad y de qué tan relacionados estén los datos porque está conceptualizando el tipo. También le permite devolver la columna artificial al programa de consulta para que tenga un contexto por el que pueda ordenar u organizar.

Pero de esta manera tiene la ventaja de ser rápido, no introducir variables adicionales y facilitar la separación de cada consulta, incluida la clasificación. La capacidad de agregar un límite es simplemente una bonificación extra.

Y, por supuesto, siéntase libre de convertir toda la unión en una unión y agregar un tipo para toda la consulta. O agregue una identificación artificial, en cuyo caso de esta manera es más fácil ordenar por diferentes parámetros en cada consulta, pero de lo contrario es lo mismo que la respuesta aceptada.

Gerard ONeill
fuente
4

Obtuve esto trabajando en una unión más unión.

(SELECT 
   table1.column1,
   table1.column2,
   foo1.column4
 FROM table1, table2, foo1, table5
 WHERE table5.somerecord = table1.column1
 ORDER BY table1.column1 ASC, table1.column2 DESC
)

UNION

(SELECT
    ... Another complex query as above
)

ORDER BY column1 DESC, column2 ASC
Robert Saylor
fuente
3

Cuando utiliza una ORDER BYcláusula dentro de una subconsulta utilizada junto con un UNIONmysql, se optimizará la ORDER BYcláusula.

Esto se debe a que, de forma predeterminada, a UNIONdevuelve una lista desordenada, por lo ORDER BYque no haría nada.

La optimización se menciona en los documentos y dice:

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 sentencias SELECT individuales no implica nada sobre el orden en que aparecen las filas en el resultado final porque UNION por defecto produce un conjunto de filas desordenadas. Por lo tanto, el uso de ORDER BY en este contexto generalmente está en conjunción con LIMIT, de modo 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.

La última oración de esto es un poco engañosa porque debería tener un efecto. Esta optimización causa un problema cuando se encuentra en una situación en la que necesita ordenar dentro de la subconsulta.

Para obligar a MySQL a no hacer esta optimización, puede agregar una cláusula LIMIT de la siguiente manera:

(SELECT 1 AS rank, id, add_date FROM my_table WHERE distance < 5 ORDER BY add_date LIMIT 9999999999)
UNION ALL
(SELECT 2 AS rank, id, add_date FROM my_table WHERE distance BETWEEN 5 AND 15 ORDER BY rank LIMIT 9999999999)
UNION ALL
(SELECT 3 AS rank, id, add_date from my_table WHERE distance BETWEEN 5 and 15 ORDER BY id LIMIT 9999999999)

Un valor alto LIMITsignifica que puede agregar un OFFSETen la consulta general si desea hacer algo como la paginación.

Esto también le brinda el beneficio adicional de poder ORDER BYcrear diferentes columnas para cada unión.

hdifeno
fuente
0

Tratar:

SELECT result.* 
FROM (
 [QUERY 1]
 UNION
 [QUERY 2]
) result
ORDER BY result.id

Donde [QUERY 1] y [QUERY 2] son ​​sus dos consultas que desea fusionar.

André Hoffmann
fuente
0

Esto se debe a que está ordenando todo el conjunto de resultados, debe ordenar cada parte de la unión por separado, o puede usar la cláusula ORDER BY (algo, es decir, distancia de consulta) ENTONCES (algo, es decir, id de fila)

canni
fuente
0

Intenté agregar el orden a cada una de las consultas antes de unir como

(select * from table where distance=0 order by add_date) 
union 
(select * from table where distance>0 and distance<=5 order by add_date)

Pero no parecía funcionar. En realidad, no hizo el pedido dentro de las filas de cada selección.

Creo que tendrá que mantener el orden en el exterior y agregar las columnas en la cláusula where al orden, algo así como

(select * from table where distance=0) 
union 
(select * from table where distance>0 and distance<=5) 
order by distance, add_date

Esto puede ser un poco complicado, ya que desea agrupar por rangos, pero creo que debería ser factible.

Mike C
fuente
La idea de user151841 union_sort a continuación sería una buena manera de manejar la agrupación
Mike C