web-dev-qa-db-fra.com

Utiliser union et order by clause dans mysql

Je veux utiliser order by avec l'union dans la requête mysql. Je récupère différents types d'enregistrements en fonction de différents critères d'un tableau en fonction de la distance pour une recherche sur mon site. La première requête de sélection renvoie des données relatives à la recherche de lieu exacte. La deuxième requête de sélection renvoie des données relatives à la distance dans un rayon de 5 km du lieu recherché. La troisième requête de sélection renvoie les données relatives à la distance dans un rayon de 5 à 15 km du lieu recherché.

Ensuite, j’utilise union pour fusionner tous les résultats et les afficher sur une page avec pagination. Sous la rubrique appropriée, sous la forme 'Résultats de la recherche exacte', 'Résultats dans un rayon de 5 km' etc.

Maintenant, je veux trier les résultats basés sur id ou add_date. Mais quand j'ajoute order by clause à la fin de ma requête (requête1 union requête 2 union requête 3 commande par add_date). Il trie tous les résultats. Mais ce que je veux, c'est qu'il faille trier chaque titre.

115
Aditya

Vous pouvez le faire en ajoutant une pseudo-colonne nommée rang à chaque sélection, que vous pouvez trier en premier, avant de trier vos autres critères, par exemple:

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
207
RedFilter

Vous pouvez utiliser des sous-requêtes pour cela:

select * from (select values1 from table1 order by orderby1) as a
union all
select * from (select values2 from table2 order by orderby2) as b
40
rickythefox
(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
25
Mitali

N'oubliez pas que l'union de tous est un moyen d'ajouter des enregistrements à un jeu d'enregistrements sans trier ni fusionner (par opposition à l'union).

Donc par exemple:

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

Il maintient les requêtes individuelles plus claires et vous permet de trier différents paramètres dans chaque requête. Cependant, en utilisant la façon dont la réponse est sélectionnée, cela peut devenir plus clair en fonction de la complexité et de la corrélation entre les données, car vous conceptualisez le tri. Il vous permet également de renvoyer la colonne artificielle au programme d'interrogation afin que celui-ci dispose d'un contexte dans lequel trier ou organiser.

Mais cette méthode présente l’avantage d’être rapide, de ne pas introduire de variables supplémentaires et de faciliter la séparation de chaque requête, y compris le tri. La possibilité d'ajouter une limite est tout simplement un bonus supplémentaire.

Et bien sûr, sentez-vous libre de transformer le syndicat en syndicat et d'ajouter une sorte pour toute la requête. Vous pouvez également ajouter un identifiant artificiel. Dans ce cas, cette méthode facilite le tri en fonction de paramètres différents dans chaque requête, mais correspond autrement à la réponse acceptée.

8
Gerard ONeill

Une requête d'union ne peut avoir qu'un seul maître ORDER BY clause, IIRC. Pour obtenir cela, dans chaque requête constituant la plus grande requête UNION, ajoutez un champ qui sera celui que vous trierez pour le UNION's ORDER BY.

Par exemple, vous pourriez avoir quelque chose comme

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

Cette union_sort vous pouvez trier ce que vous voulez trier. Dans cet exemple, il arrive simplement de mettre les résultats du premier tableau en premier, du deuxième tableau en second, etc.

8
user151841

Je travaille sur un syndicat d'adhésion.

(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
4
Robert Saylor

Essayer:

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

Où [QUERY 1] et [QUERY 2] sont vos deux requêtes que vous souhaitez fusionner.

0
André Hoffmann

En effet, vous devez trier l'intégralité de l'ensemble de résultats, vous devez trier chaque partie de l'union séparément ou vous pouvez utiliser la clause ORDER BY (quelque chose, par exemple, la distance d'une sous-requête) THEN (quelque chose, par exemple, l'identificateur de ligne).

0
canni

J'ai essayé d'ajouter l'ordre à chacune des questions avant de l'union comme

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

mais cela n'a pas semblé fonctionner. Il n'a pas réellement effectué l'ordre dans les lignes de chaque sélection.

Je pense que vous devrez garder l'ordre de l'extérieur et ajouter les colonnes de la clause where à l'ordre de, quelque chose comme:

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

Cela peut être un peu délicat, car vous voulez grouper par plages, mais je pense que cela devrait être faisable.

0
Mike C

Lorsque vous utilisez une clause ORDER BY Dans une sous-requête utilisée conjointement avec un UNION mysql, la clause ORDER BY Sera optimisée.

En effet, par défaut, UNION renvoie une liste non ordonnée. Par conséquent, un ORDER BY Ne ferait rien.

L'optimisation est mentionnée dans la documentation et dit:

Pour appliquer ORDER BY ou LIMIT à un SELECT individuel, placez la clause entre les parenthèses entourant le 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);

Toutefois, l'utilisation de ORDER BY pour des instructions SELECT individuelles n'implique en aucune manière l'ordre dans lequel les lignes apparaissent dans le résultat final, car UNION génère par défaut un ensemble de lignes non ordonné. Par conséquent, l'utilisation de ORDER BY dans ce contexte est généralement associée à LIMIT, de sorte qu'elle est utilisée pour déterminer le sous-ensemble des lignes sélectionnées à extraire pour SELECT, même si cela n'affecte pas nécessairement l'ordre de ces lignes dans le répertoire. résultat final UNION. Si ORDER BY apparaît sans limite dans un SELECT, il est optimisé car il n’aura aucun effet de toute façon.

La dernière phrase de cette phrase est un peu trompeuse car elle devrait avoir un effet. Cette optimisation pose un problème lorsque vous êtes dans une situation où vous devez passer commande dans la sous-requête.

Pour forcer MySQL à ne pas faire cette optimisation, vous pouvez ajouter une clause LIMIT comme ceci:

(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 LIMIT élevé signifie que vous pouvez ajouter un OFFSET à la requête globale si vous souhaitez effectuer une opération telle que la pagination.

Cela vous donne également l’avantage supplémentaire de pouvoir ORDER BY Différentes colonnes pour chaque union.

0
hdifen