Como concatenar conjuntos de resultados inteiros no MySQL?
Pergunta
Estou testando a seguinte consulta:
SELECT A,B,C FROM table WHERE field LIKE 'query%'
UNION
SELECT A,B,C FROM table WHERE field LIKE '%query'
UNION
SELECT A,B,C FROM table WHERE field LIKE '%query%'
GROUP BY B ORDER BY B ASC LIMIT 5
São três perguntas juntas, mais ou menos.No entanto, o conjunto de resultados retornado reflete os resultados da consulta nº 3 antes dos resultados da consulta nº 1, o que é indesejado.
Existe alguma maneira de priorizá-los para que os resultados sejam todos para a consulta nº 1, depois todos para a consulta nº 2 e depois todos para a consulta nº 3?Não quero fazer isso em PHP ainda (sem falar em ter que controlar os resultados que apareceram na primeira consulta para não aparecerem na segunda e assim por diante).
Solução
Talvez você devesse tentar incluir uma quarta coluna, informando a tabela de onde ela veio, e então ordenar e agrupar por ela:
SELECT A,B,C, "query 1" as origin FROM table WHERE field LIKE 'query%'
UNION
SELECT A,B,C, "query 2" as origin FROM table WHERE field LIKE '%query'
UNION
SELECT A,B,C, "query 3" as origin FROM table WHERE field LIKE '%query%'
GROUP BY origin, B ORDER BY origin, B ASC LIMIT 5
Outras dicas
Adicione uma coluna adicional com valores codificados que você usará para classificar o conjunto de resultados geral, assim:
SELECT A,B,C,1 as [order] FROM table WHERE field LIKE 'query%'
UNION
SELECT A,B,C,2 as [order] FROM table WHERE field LIKE '%query'
UNION
SELECT A,B,C,3 as [order] FROM table WHERE field LIKE '%query%'
GROUP BY B ORDER BY [order] ASC, B ASC LIMIT 5
Você pode fazer isso como uma subseleção, algo como
SELECT * FROM (
SELECT A,B,C FROM table WHERE field LIKE 'query%'
UNION
SELECT A,B,C FROM table WHERE field LIKE '%query'
UNION
SELECT A,B,C FROM table WHERE field LIKE '%query%'
) ORDER BY B ASC LIMIT 5
Selecione distinto a, b, c de (selecione a, b, c, 1 como o da tabela onde campo como 'consulta%' união selecione a, b, c, 2 como o da tabela, onde o campo como '%consulta' união selecionar A, b, c, 3 como o da tabela onde o campo como '%consulta%') ordem por o limite asc 5
Seria a minha maneira de fazer isso.Eu não sei como isso escala.
Eu não entendo o
GROUP BY B ORDER BY B ASC LIMIT 5
Aplica-se apenas ao último SELECT da união?
O mysql realmente permite agrupar por uma coluna e ainda não agregar nas outras colunas?
EDITAR:aahh.Vejo que o mysql realmente faz.É uma versão especial do DISTINCT(b) ou algo assim.Eu não gostaria de tentar ser um especialista nessa área :)
Se não houver uma classificação que faça sentido ordená-los, não junte os resultados - apenas retorne três conjuntos de registros separados e lide com eles adequadamente em sua camada de dados.
Eventualmente (olhando todas as sugestões) cheguei a esta solução, é um meio-termo entre o que preciso e o tempo.
SELECT * FROM
(SELECT A, B, C, "1" FROM table WHERE B LIKE 'query%' LIMIT 3
UNION
SELECT A, B, C, "2" FROM table WHERE B LIKE '%query%' LIMIT 5)
AS RS
GROUP BY B
ORDER BY 1 DESC
entrega 5 resultados no total, classifica a partir da quarta "coluna" e me dá o que preciso;um conjunto de resultados naturais (está vindo do AJAX) e um conjunto de resultados curinga logo em seguida.
:)
/mp
Existem duas variantes de UNION.
'UNION' and 'UNION ALL'
Na maioria dos casos, o que você realmente quer dizer é UNION ALL, pois não elimina duplicatas (pense SELECT DISTINCT
) entre conjuntos, o que pode resultar em uma grande economia em termos de tempo de execução.
Outros sugeriram vários conjuntos de resultados, o que é uma solução viável, no entanto, eu alertaria contra isso em aplicativos sensíveis ao tempo ou aplicativos conectados por WANs, pois isso pode resultar em significativamente mais viagens de ida e volta na rede entre o servidor e o cliente.
Não entendo porque a necessidade de união para retirar os dados de uma única tabela
SELECT A
,B
,C
FROM table
WHERE field LIKE 'query%' or field LIKE '%query' or field LIKE '%query%'
GROUP BY B ORDER BY B ASC LIMIT 5