ChatGPT解决这个技术问题 Extra ChatGPT

How to order by with union in SQL?

Is it possible to order when the data is come from many select and union it together? Such as

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

How can I order this query by name?

I tried this

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

But that does not work.

If you have the same column in union query then at the end put order by your column name.

b
bernd_k

Just write

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

the order by is applied to the complete resultset


What if I want the sort to be applied on only the top one of the UNION ?
@marifrahman see my answer stackoverflow.com/a/43855496/2340825
@marifrahman sorry to dig an old topic, but it may help others. In case you want the ORDER BY to be applied to the first part of the UNION, protect this SELECT with parenthesis.
What if you don't want to have name be returned though? Can you provide an alias to both tables to ORDER BY but omit it from the resultset?
M
Mark Robinson
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

As bernd_k pointed out, by definition, the individual SELECTs making up a UNION are not allowed to contain an ORDER BY clause. The only ORDER BY clause allowed is at the end of the UNION and it applies to the entire UNION, making xxx UNION yyy ORDER BY zzz the eqivalent of (xxx UNION yyy) ORDER BY zzz
n
nik7

In order to make the sort apply to only the first statement in the UNION, you can put it in a subselect with UNION ALL (both of these appear to be necessary 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%"

Or (addressing Nicholas Carey's comment) you can guarantee the top SELECT is ordered and results appear above the bottom SELECT like this:

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

Yes. That orders the the results of the subselect. That does NOT order the results of the select statement referencing that subselect. Per the SQL Standard, the order of results is undefined barring an explicit order by clause. That first select in your example probably returns its results in the order returned by the subselect, but it is not guaranteed. Further, that does *not* guarantee the ordering of the result set of the entire union (same rule in the Standard). If you are depending on the order, you will — eventually — get bitten.
@Nicholas Carey - when I initially tested using a UNION it was behaving unpredictably as you described, I think the UNION ALL (at least in Oracle) was necessary to order the top SELECT above the bottom. However I've provided an alternate that does guarantee correct ordering and should be database independent.
Not working for me. The one with UNION ALL still fails to maintain the order within the first SELECT.
And the problem with the second query is, it does not eliminate the duplicate records. Because you have added another column 'rowOrder' which might have different value against the duplicate records. Purpose of UNION against UNION ALL is lost.
@AmitChigadani Elimination of duplicates wasn't part of the original question, but to do so the WHERE clauses can be modified to ensure uniqueness. eg: Where Name like "%a%" AND age >= 15
C
Conrad37

As other answers stated, ORDER BY after the last UNION should apply to both datasets joined by union.

I had two datasets using different tables but the same columns. ORDER BY after the last UNION still didn't work.

Using an alias for the column used in the ORDER BY clause did the trick.

SELECT Name, Address FROM Employee 
UNION
SELECT Customer_Name, Address FROM Customer
ORDER BY customer_name;   --Won't work

The solution was to use the alias User_Name, shown below:

SELECT Name AS User_Name, Address FROM Employee 
UNION
SELECT Customer_Name AS User_Name, Address FROM Customer
ORDER BY User_Name; 

don't do the trick in spark SQL : mismatched input 'FOR' expecting <EOF>
maybe mistype, should be from, not for, in first line of both examples?
This was the answer that helped me the most, as I was using an alias in my query but then trying to ORDER BY the original column name. It was the same column name in both parts of the UNION but because I had named it with an alias, it was looking for that specific alias I had used. So just a warning for others: if you use aliases in a UNION and want to ORDER BY that column, make sure you ORDER BY the Alias.
m
moonvader

Both other answers are correct, but I thought it worth noting that the place where I got stuck was not realizing that you'll need order by the alias and make sure that the alias is the same for both the selects... so

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

notice that I'm using single quotes in the first select but backticks for the others.

That will get you the sorting you need.


what's the important you want to make with using single quote in first select and backticks in other? Ideally it should be consistent.
The first select is a literal; it's a header like 'NAMES'. The second select is a reference to a table. So your first row will say "NAMES" and the rest of the rows will be the actual names selected from the table. The point is that your header may very well be the same string as the name of the column from which you're selecting and this is the solution for using the label you want without it colliding in your union.
After some experimentation I see that the alias mentioned in the ORDER BY clause must be mentioned in the SELECT clauses. You can't sort by another column. Of course you can work around that by wrapping the whole thing in a SELECT a, b, c FROM (<insert union query here>) AS x; if you really want to avoid returning the extra column.
S
SvenBM

Order By is applied after union, so just add an order by clause at the end of the statements:

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

n
nik7

If I want the sort to be applied to only one of the UNION if use 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
)

E
Edward

To add to an old topic, I used ROW_NUMBER (using MS SQL). This allows sorts (orders) within UNIONs. So using an idea from @BATabNabber to separate each half of the Union, and @Wodin of wrapping the whole thing in a select, I got:

Select Id, Name, Age from
(
Select Id, Name, Age, 1 as Mainsort
 , ROW_NUMBER() over (order by age) as RowNumber
From Student
Where Age < 15

Union

Select Id, Name, Age, 2 as Mainsort
 , ROW_NUMBER() over (Order by Name) as RowNumber
From Student
Where Name like '%a%'
) as x
Order by Mainsort, RowNumber

So adjust, or omit, what you want to Order by, and add Descendings as you see fit.


Please add code and data as text (using code formatting), not images. Images: A) don't allow us to copy-&-paste the code/errors/data for testing; B) don't permit searching based on the code/error/data contents; and many more reasons. Images should only be used, in addition to text in code format, if having the image adds something significant that is not conveyed by just the text code/error/data.
Ω
ΩmegaMan

Add a column to the query which can sub identify the data to sort on that.

In the below example I use a Common Table Expression with the selects what you showed and places them into specific groups on the CTE; then do a union off of both of those groups into AllStudents.

The final select will then sort AllStudents by the SortIndex column first and then by the name such as:

WITH Juveniles as
(
      Select 1 as [SortIndex], id,name,age From Student
      Where age < 15
),

AStudents as
(
      Select 2 as [SortIndex], id,name,age From Student
      Where Name like "%a%" 
),

AllStudents as
(
      select * from Juveniles
      union 
      select * from AStudents
)

select * from AllStudents
sort by [SortIndex], name;

To summarize, it will get all the students which will be sorted by group first, and subsorted by the name within the group after that.


K
Koushik Roy

To apply an ORDER BY or LIMIT clause to an individual SELECT, parenthesize the SELECT and place the clause inside the parentheses:

(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);


Works with PostgreSQL
A
Ahmad Aghazadeh

Can use this:

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

F
Fandango68

Why not use TOP X?

SELECT pass1.* FROM 
 (SELECT TOP 2000000 tblA.ID, tblA.CustomerName 
  FROM TABLE_A AS tblA ORDER BY 2) AS pass1
UNION ALL 
SELECT pass2.* FROM 
  (SELECT TOP 2000000 tblB.ID, tblB.CustomerName 
   FROM TABLE_B AS tblB ORDER BY 2) AS pass2

The TOP 2000000 is an arbitrary number, that is big enough to capture all of the data. Adjust as per your requirements.


"top 100 percent" is better.
There are issues with "top 100 percent". See above links
Interresting. Where are the links?
Hmm someone removed their comment it seems. Ok here: stackoverflow.com/questions/1393508/… and here sqlshack.com/… It's all to do with performance, depending on indexes.