Comment commander par avec union en SQL?

202

Est-il possible de commander lorsque les données proviennent de nombreuses personnes sélectionnées et réunies? Tel que

Select id,name,age
From Student
Where age < 15
Union
Select id,name,age
From Student
Where Name like "%a%"

Comment puis-je commander cette requête par nom.

Certains ont dit que vous pouvez interroger cela.

Select id,name,age
From Student
Where age < 15 or name like "%a%"
Order by name

Mais dans ce cas, j'ignore simplement cette solution.

Guilgamos
la source
1
Si vous avez la même colonne dans la requête d'union, à la fin, mettez l'ordre par le nom de votre colonne.
anirban karak

Réponses:

266

Ecrivez

Select id,name,age
From Student
Where age < 15
Union
Select id,name,age
From Student
Where Name like "%a%"
Order by name

l'ordre par est appliqué au jeu de résultats complet

bernd_k
la source
45
Que faire si je souhaite que le tri soit appliqué uniquement sur le sommet de l'UNION?
marifrahman
7
@marifrahman voir ma réponse stackoverflow.com/a/43855496/2340825
BA TabNabber
2
@marifrahman désolé de creuser un vieux sujet, mais cela peut aider les autres. Si vous souhaitez que ORDER BY soit appliqué à la première partie de l'UNION, protégez ce SELECT entre parenthèses.
Lideln Kyoku
82
Select id,name,age
from
(
   Select id,name,age
   From Student
   Where age < 15
  Union
   Select id,name,age
   From Student
   Where Name like "%a%"
) results
order by name
Mark Robinson
la source
46
Comme l'a souligné bernd_k, par définition, les SELECT individuels constituant une UNION ne sont pas autorisés à contenir une clause ORDER BY. La seule clause ORDER BY autorisée se trouve à la fin de l'UNION et s'applique à l'ensemble de l'UNION, ce qui fait xxx UNION yyy ORDER BY zzzl'équivalent de(xxx UNION yyy) ORDER BY zzz
Nicholas Carey
39

Pour que le tri s'applique uniquement à la première instruction dans UNION, vous pouvez le placer dans une sous-sélection avec UNION ALL (les deux semblent nécessaires dans Oracle):

Select id,name,age FROM 
(    
 Select id,name,age
 From Student
 Where age < 15
 Order by name
)
UNION ALL
Select id,name,age
From Student
Where Name like "%a%"

Ou (répondant au commentaire de Nicholas Carey), vous pouvez garantir que le SELECT supérieur est commandé et les résultats apparaissent au-dessus du SELECT inférieur comme ceci:

Select id,name,age, 1 as rowOrder
From Student
Where age < 15
UNION
Select id,name,age, 2 as rowOrder
From Student
Where Name like "%a%"
Order by rowOrder, name
BA TabNabber
la source
4
Oui. Cela ordonne les résultats de la sous-sélection. Cela n'ordonne PAS les résultats de l' selectinstruction faisant référence à cette sous-sélection. Selon la norme SQL, l'ordre des résultats n'est pas défini sauf une order byclause explicite . Le premier selectdans votre exemple renvoie probablement ses résultats dans l'ordre renvoyé par la sous-sélection, mais ce n'est pas garanti. De plus, cela ne garantit * pas * la commande de l'ensemble de résultats de l'ensemble union(même règle dans la norme). Si vous dépendez de la commande, vous finirez par vous faire mordre.
Nicholas Carey
1
@Nicholas Carey - lorsque j'ai d'abord testé en utilisant un UNION, il se comportait de façon imprévisible comme vous l'avez décrit, je pense que l'UNION ALL (au moins dans Oracle) était nécessaire pour commander le haut SELECT au-dessus du bas. Cependant, j'ai fourni une alternative qui garantit un bon ordre et devrait être indépendante de la base de données.
BA TabNabber
Ne travaille pas pour moi. Celui avec UNION ALL ne parvient toujours pas à maintenir l'ordre dans le premier SELECT.
Amit Chigadani
Et le problème avec la deuxième requête est qu'elle n'élimine pas les enregistrements en double. Parce que vous avez ajouté une autre colonne 'rowOrder' qui peut avoir une valeur différente par rapport aux enregistrements en double. Le but d'UNION contre UNION ALL est perdu.
Amit Chigadani
1
@AmitChigadani L'élimination des doublons ne faisait pas partie de la question d'origine, mais pour ce faire, les clauses WHERE peuvent être modifiées pour garantir l'unicité. Par exemple: où le nom comme "% a%" ET l'âge> = 15
BA TabNabber
12

Les deux autres réponses sont correctes, mais j'ai pensé qu'il valait la peine de noter que l'endroit où je suis resté coincé ne se rendait pas compte que vous aurez besoin de l'ordre par l'alias et assurez-vous que l'alias est le même pour les deux sélections ... donc

select 'foo'
union
select item as `foo`
from myTable
order by `foo`

notez que j'utilise des guillemets simples dans la première sélection mais des crochets pour les autres.

Vous obtiendrez ainsi le tri dont vous avez besoin.

Yevgeny Simkin
la source
quel est l’important que vous voulez faire avec l’utilisation de guillemets simples dans la première sélection et les retours en arrière dans les autres? Idéalement, il devrait être cohérent.
nanosoft
Le premier choix est un littéral; c'est un en-tête comme «NOMS». La deuxième sélection est une référence à une table. Ainsi, votre première ligne indiquera "NOMS" et les autres lignes seront les noms réels sélectionnés dans le tableau. Le fait est que votre en-tête peut très bien être la même chaîne que le nom de la colonne à partir de laquelle vous sélectionnez et c'est la solution pour utiliser l'étiquette que vous voulez sans qu'elle entre en collision dans votre union.
Yevgeny Simkin
2
Après quelques expérimentations, je constate que l'alias mentionné dans la clause ORDER BY doit être mentionné dans les clauses SELECT. Vous ne pouvez pas trier par une autre colonne. Bien sûr, vous pouvez contourner cela en enveloppant le tout dans un SELECT a, b, c FROM (<insert union query here>) AS x;si vous voulez vraiment éviter de renvoyer la colonne supplémentaire.
Wodin
11

Order Byest appliqué après union, il suffit donc d'ajouter une order byclause à la fin des instructions:

Select id,name,age
From Student
Where age < 15
Union
Select id,name,age
From Student
Where Name like '%a%'
Order By name
Sunil Kumar
la source
9

Si je veux que le tri soit appliqué à un seul de l'UNION si vous utilisez Union all:

Select id,name,age
From Student
Where age < 15
Union all
Select id,name,age
From 
(
Select id,name,age
From Student
Where Name like "%a%"
Order by name
)
osydorchuk
la source
8

Comme d'autres réponses l'ont indiqué, «Trier par» après LAST Union devrait s'appliquer aux deux ensembles de données joints par union.

J'avais deux ensembles de données mais j'utilisais des tables différentes mais les mêmes colonnes. «Commander avant» après que LAST Union n'ait pas encore fonctionné. L'utilisation d'ALIAS pour la colonne utilisée dans l'ordre par a fait l'affaire.

Select Name, Address for Employee 
Union
Select Customer_Name, Address from Customer
order by customer_name;   --Won't work

La solution consiste donc à utiliser l'alias 'User_Name':

Select Name as User_Name, Address for Employee 
Union
Select Customer_Name as User_Name, Address from Customer
order by User_Name; 
Mandragore
la source
-1

Peut utiliser ceci:

Select id,name,age
From Student
Where age < 15
Union ALL
SELECT * FROM (Select id,name,age
From Student
Where Name like "%a%")
Ahmad Aghazadeh
la source