Come ordinare con union in SQL?


202

È possibile ordinare quando i dati provengono da molti utenti selezionati e unirli? Ad esempio

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

Come posso ordinare questa query per nome.

Alcuni hanno detto che puoi eseguire una query simile a questa.

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

Ma in questo caso ignoro solo quella soluzione.


1
Se hai la stessa colonna nella query di unione, alla fine metti l'ordine con il nome della tua colonna.
Anirban Karak,

Risposte:


266

Scrivi e basta

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

l'ordine per viene applicato al set di risultati completo


45
Cosa succede se desidero applicare l'ordinamento solo su quello superiore dell'UNION?
marifrahman,

7
@marifrahman vedi la mia risposta stackoverflow.com/a/43855496/2340825
BA TabNabber

2
@marifrahman mi dispiace scavare un vecchio argomento, ma può aiutare gli altri. Nel caso in cui si desideri applicare ORDER BY alla prima parte di UNION, proteggere questo SELECT tra parentesi.
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

46
Come sottolineato da bernd_k, per definizione, i singoli SELECT che compongono un UNION non possono contenere una clausola ORDER BY. L'unica clausola ORDER BY consentita è alla fine dell'UNIONE e si applica all'intera UNIONE, rendendo xxx UNION yyy ORDER BY zzzl'equivalente di(xxx UNION yyy) ORDER BY zzz
Nicholas Carey il

39

Per fare in modo che l'ordinamento si applichi solo alla prima istruzione in UNION, è possibile inserirlo in una sottoselezione con UNION ALL (entrambi sembrano necessari in 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%"

Oppure (rivolgendosi al commento di Nicholas Carey) puoi garantire che il SELECT in alto sia ordinato e che i risultati vengano visualizzati sopra il SELECT in questo modo:

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

4
Sì. Ciò ordina i risultati della sottoselezione. Ciò NON ordina i risultati selectdell'istruzione che fa riferimento a quella selezione secondaria. Secondo lo standard SQL, l'ordine dei risultati è indefinito salvo una order byclausola esplicita . Quello primo selectnel tuo esempio probabilmente restituisce i suoi risultati nell'ordine restituito dalla sottoselezione, ma non è garantito. Inoltre, ciò * non * garantisce l'ordinamento dell'insieme di risultati dell'intero union(stessa regola nello standard). Se dipendi dall'ordine, alla fine verrai morso.
Nicholas Carey,

1
@ Nicholas Carey - quando inizialmente ho provato a utilizzare UNION si comportava in modo imprevedibile come hai descritto, penso che UNION ALL (almeno in Oracle) fosse necessario per ordinare il SELECT in alto sopra il fondo. Tuttavia, ho fornito un sostituto che garantisce l'ordinamento corretto e dovrebbe essere indipendente dal database.
BA TabNabber,

Non funziona per me. Quello con UNION ALL non riesce ancora a mantenere l'ordine entro il primo SELECT.
Amit Chigadani,

E il problema con la seconda query è che non elimina i record duplicati. Perché hai aggiunto un'altra colonna 'rowOrder' che potrebbe avere un valore diverso rispetto ai record duplicati. Lo scopo di UNION contro UNION ALL è perduto.
Amit Chigadani,

1
@AmitChigadani L'eliminazione dei duplicati non faceva parte della domanda originale, ma per fare ciò le clausole WHERE possono essere modificate per garantire unicità. ad es .: dove Nome come "% a%" E età> = 15
BA TabNabber

12

Entrambe le altre risposte sono corrette, ma ho pensato che valesse la pena notare che il posto in cui mi sono bloccato non si rendeva conto che avresti bisogno dell'alias e assicurati che l'alias sia lo stesso per entrambe le selezioni ... quindi

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

nota che sto usando le virgolette singole nella prima selezione ma i backtick per le altre.

Questo ti darà l'ordinamento di cui hai bisogno.


qual è l'importante che vuoi fare usando la virgoletta singola nella prima selezione e i backtick nell'altra? Idealmente dovrebbe essere coerente.
nanosoft,

La prima selezione è letterale; è un'intestazione come "NAMES". La seconda selezione è un riferimento a una tabella. Quindi la tua prima riga dirà "NOMES" e il resto delle righe saranno i nomi effettivi selezionati dalla tabella. Il punto è che l'intestazione potrebbe benissimo essere la stessa stringa del nome della colonna da cui stai selezionando e questa è la soluzione per usare l'etichetta che desideri senza che si scontrino nella tua unione.
Evgenij Simkin il

2
Dopo alcuni esperimenti, vedo che l'alias menzionato nella clausola ORDER BY deve essere menzionato nelle clausole SELECT. Non puoi ordinare per un'altra colonna. Ovviamente puoi aggirare il problema avvolgendo il tutto in un SELECT a, b, c FROM (<insert union query here>) AS x;se vuoi davvero evitare di restituire la colonna aggiuntiva.
Wodin,

11

Order Byviene applicato dopo union, quindi basta aggiungere una order byclausola alla fine delle istruzioni:

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

9

Se voglio che l'ordinamento venga applicato solo a una delle UNION se uso 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
)

8

Come indicato da altre risposte, "Ordina per" dopo LAST Union dovrebbe applicarsi a entrambi i set di dati uniti da union.

Avevo due set di dati ma utilizzavo tabelle diverse ma stesse colonne. "Ordina per" dopo che LAST Union non ha ancora funzionato. Usare ALIAS per la colonna usata in 'ordina per' ha fatto il trucco.

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

Quindi la soluzione è usare 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; 

-1

Può usare questo:

Select id,name,age
From Student
Where age < 15
Union ALL
SELECT * FROM (Select id,name,age
From Student
Where Name like "%a%")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.