Weird result with UNION and ORDER BY - mysql

I have this query (simplified):
SELECT score FROM tbl WHERE id = xx ORDER BY score DESC;
And it works correctly. Now I add to this query an UNION like this:
(SELECT score FROM tbl WHERE id = x ORDER BY score DESC)
UNION
(SELECT score FROM tbl WHERE id = y)
Now all the first result-set of the first query is messed up not respecting the ORDER BY score DESC

SELECT score FROM tbl WHERE id = x
UNION
SELECT score FROM tbl WHERE id = y
ORDER BY score DESC;
just add the order by to the end. it will apply to the entire result set. If you want to differentiate the result add an order col like so:
SELECT 1 as order_col, score FROM tbl WHERE id = x
UNION
SELECT 2 as order_col, score FROM tbl WHERE id = y
ORDER BY order_col ,score DESC;

In a union query, the order by must be put with the last select.

Ok I found the solution.
UNION and ORDER BY isn't allowed. I can only put ORDER BY at the end of UNION

Related

Order by With Union SQL

SELECT to_user_id AS sender_id
FROM $chat_table_name
WHERE((to_user_id = $current_user_id OR from_user_id = $current_user_id) and post_id=$post_id)
UNION
SELECT from_user_id AS receiver_id
FROM $chat_table_name
WHERE( (from_user_id = $current_user_id OR to_user_id = $current_user_id) and post_id=$post_id )
order by chat_message_id DESC
How to achieve order by with this query
If I get your question correct, you want to order the indivual SELECTs seperately and you cannot use two ORDER BY clause per each statement instead, add an extra integer column to each SELECT as shown below:
SELECT *, 1 as orderBy from t1
UNION ALL
SELECT *, 2 as orderBy from t2
ORDER BY orderBy desc.

Is it possible to do this task more efficiently? MySQL

Currently, I have a task: for the presented table, to change students' order by replacing odd and even sequence (example below). There is only one condition, if the number of students is odd, that last number should not be changed. I currently wrote a code like this, however, for me, it seems pretty clumsy. How different and more efficient should this code be written?
CREATE TABLE student (id int, name varchar(128));
INSERT INTO student (id,name) VALUES
(1,'Aurimas'),
(2,'Darius'),
(3,'Eligijus'),
(4,'Giedrius'),
(5,'Justinas');
SELECT CASE
WHEN mod((SELECT id FROM student ORDER BY id DESC LIMIT 1),2) = 0 THEN
CASE
WHEN mod(id, 2) = 0 THEN id-1
ELSE id=id+1
END
ELSE
CASE
WHEN mod(id, 2) = 0 AND id <> (SELECT id FROM student ORDER BY id DESC LIMIT 1) THEN id-1
WHEN mod(id, 2) = 1 AND id <> (SELECT id FROM student ORDER BY id DESC LIMIT 1) THEN id+1
ELSE id
END
END AS new_id, name
FROM student
ORDER BY new_id ASC;
I have this:
id name
1 Aurimas
2 Darius
3 Eligijus
4 Giedrius
5 Justinas
And it should look like this:
id name
1 Darius
2 Aurimas
3 Giedrius
4 Eligijus
5 Justinas
You could group your ids by the value of (id+1) DIV 2. Then all you have to do is swap the minimum id with the maximum id in each pair of rows and make sure you handle the case when there are odd number of rows properly.
Something like this:
set #maxId = (select max(id) from student);
select
if (
#maxId = id and mod(id, 2) != 0,
id,
if (
mod((id+1), 2) = 0,
id+1,
id-1
)
) as id,
name
from student
order by id;
db<>fiddle
I'm not sure how you're defining 'efficient', but how about...
select ROW_NUMBER() OVER (
ORDER BY ceiling(id/2), id desc
) new_id,name from student
The ROW_NUMBER function has been supported in MySQL since version 8.0.
EDIT: I suppose something like will satisfy the quibblers...
WITH cte (id,n) AS (SELECT id, ROW_NUMBER() OVER (ORDER BY id) n FROM student)
SELECT x.name
, ROW_NUMBER() OVER (ORDER BY CEILING(cte.n/2), x.id desc) new_id
FROM student x
JOIN cte
ON cte.id = x.id;
I would recommend to use the below query because
it has many advantages here I am calculating only one max id select but in your case for every case, one select will execute this will reduce that time and only one max id will be used for the odd case
your odd and even operation is the same but in odd you are skipping last record so I added that condition
SET #MAXID = (SELECT MAX(ID) FROM STUDENT);
SELECT
CASE
WHEN MOD(#MAXID,2) != 0 AND ID=#MAXID THEN ID
ELSE CASE WHEN MOD(ID, 2) = 0 THEN ID-1 ELSE ID+1 END
END AS NEW_ID, NAME
FROM STACK_USER.STUDENT
ORDER BY NEW_ID ASC;
I think this would be useful in your case I have checked every condition in my local it will work properly
Screen Shot For Better Understanding:

Query to fetch second highest salary from table [duplicate]

What is the simplest SQL query to find the second largest integer value in a specific column?
There are maybe duplicate values in the column.
SELECT MAX( col )
FROM table
WHERE col < ( SELECT MAX( col )
FROM table )
SELECT MAX(col)
FROM table
WHERE col NOT IN ( SELECT MAX(col)
FROM table
);
In T-Sql there are two ways:
--filter out the max
select max( col )
from [table]
where col < (
select max( col )
from [table] )
--sort top two then bottom one
select top 1 col
from (
select top 2 col
from [table]
order by col) topTwo
order by col desc
In Microsoft SQL the first way is twice as fast as the second, even if the column in question is clustered.
This is because the sort operation is relatively slow compared to the table or index scan that the max aggregation uses.
Alternatively, in Microsoft SQL 2005 and above you can use the ROW_NUMBER() function:
select col
from (
select ROW_NUMBER() over (order by col asc) as 'rowNum', col
from [table] ) withRowNum
where rowNum = 2
I see both some SQL Server specific and some MySQL specific solutions here, so you might want to clarify which database you need. Though if I had to guess I'd say SQL Server since this is trivial in MySQL.
I also see some solutions that won't work because they fail to take into account the possibility for duplicates, so be careful which ones you accept. Finally, I see a few that will work but that will make two complete scans of the table. You want to make sure the 2nd scan is only looking at 2 values.
SQL Server (pre-2012):
SELECT MIN([column]) AS [column]
FROM (
SELECT TOP 2 [column]
FROM [Table]
GROUP BY [column]
ORDER BY [column] DESC
) a
MySQL:
SELECT `column`
FROM `table`
GROUP BY `column`
ORDER BY `column` DESC
LIMIT 1,1
Update:
SQL Server 2012 now supports a much cleaner (and standard) OFFSET/FETCH syntax:
SELECT [column]
FROM [Table]
GROUP BY [column]
ORDER BY [column] DESC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY;
I suppose you can do something like:
SELECT *
FROM Table
ORDER BY NumericalColumn DESC
LIMIT 1 OFFSET 1
or
SELECT *
FROM Table ORDER BY NumericalColumn DESC
LIMIT (1, 1)
depending on your database server. Hint: SQL Server doesn't do LIMIT.
The easiest would be to get the second value from this result set in the application:
SELECT DISTINCT value
FROM Table
ORDER BY value DESC
LIMIT 2
But if you must select the second value using SQL, how about:
SELECT MIN(value)
FROM ( SELECT DISTINCT value
FROM Table
ORDER BY value DESC
LIMIT 2
) AS t
you can find the second largest value of column by using the following query
SELECT *
FROM TableName a
WHERE
2 = (SELECT count(DISTINCT(b.ColumnName))
FROM TableName b WHERE
a.ColumnName <= b.ColumnName);
you can find more details on the following link
http://www.abhishekbpatel.com/2012/12/how-to-get-nth-maximum-and-minimun.html
MSSQL
SELECT *
FROM [Users]
order by UserId desc OFFSET 1 ROW
FETCH NEXT 1 ROW ONLY;
MySQL
SELECT *
FROM Users
order by UserId desc LIMIT 1 OFFSET 1
No need of sub queries ... just skip one row and select second rows after order by descending
A very simple query to find the second largest value
SELECT `Column`
FROM `Table`
ORDER BY `Column` DESC
LIMIT 1,1;
SELECT MAX(Salary)
FROM Employee
WHERE Salary NOT IN ( SELECT MAX(Salary)
FROM Employee
)
This query will return the maximum salary, from the result - which not contains maximum salary from overall table.
Old question I know, but this gave me a better exec plan:
SELECT TOP 1 LEAD(MAX (column)) OVER (ORDER BY column desc)
FROM TABLE
GROUP BY column
This is very simple code, you can try this :-
ex :
Table name = test
salary
1000
1500
1450
7500
MSSQL Code to get 2nd largest value
select salary from test order by salary desc offset 1 rows fetch next 1 rows only;
here 'offset 1 rows' means 2nd row of table and 'fetch next 1 rows only' is for show only that 1 row. if you dont use 'fetch next 1 rows only' then it shows all the rows from the second row.
Simplest of all
select sal
from salary
order by sal desc
limit 1 offset 1
select * from (select ROW_NUMBER() over (Order by Col_x desc) as Row, Col_1
from table_1)as table_new tn inner join table_1 t1
on tn.col_1 = t1.col_1
where row = 2
Hope this help to get the value for any row.....
Use this query.
SELECT MAX( colname )
FROM Tablename
where colname < (
SELECT MAX( colname )
FROM Tablename)
select min(sal) from emp where sal in
(select TOP 2 (sal) from emp order by sal desc)
Note
sal is col name
emp is table name
select col_name
from (
select dense_rank() over (order by col_name desc) as 'rank', col_name
from table_name ) withrank
where rank = 2
SELECT
*
FROM
table
WHERE
column < (SELECT max(columnq) FROM table)
ORDER BY
column DESC LIMIT 1
It is the most esiest way:
SELECT
Column name
FROM
Table name
ORDER BY
Column name DESC
LIMIT 1,1
As you mentioned duplicate values . In such case you may use DISTINCT and GROUP BY to find out second highest value
Here is a table
salary
:
GROUP BY
SELECT amount FROM salary
GROUP by amount
ORDER BY amount DESC
LIMIT 1 , 1
DISTINCT
SELECT DISTINCT amount
FROM salary
ORDER BY amount DESC
LIMIT 1 , 1
First portion of LIMIT = starting index
Second portion of LIMIT = how many value
Tom, believe this will fail when there is more than one value returned in select max([COLUMN_NAME]) from [TABLE_NAME] section. i.e. where there are more than 2 values in the data set.
Slight modification to your query will work -
select max([COLUMN_NAME])
from [TABLE_NAME]
where [COLUMN_NAME] IN ( select max([COLUMN_NAME])
from [TABLE_NAME]
)
select max(COL_NAME)
from TABLE_NAME
where COL_NAME in ( select COL_NAME
from TABLE_NAME
where COL_NAME < ( select max(COL_NAME)
from TABLE_NAME
)
);
subquery returns all values other than the largest.
select the max value from the returned list.
This is an another way to find the second largest value of a column.Consider the table 'Student' and column 'Age'.Then the query is,
select top 1 Age
from Student
where Age in ( select distinct top 2 Age
from Student order by Age desc
) order by Age asc
select age
from student
group by id having age< ( select max(age)
from student
)
order by age
limit 1
SELECT MAX(sal)
FROM emp
WHERE sal NOT IN ( SELECT top 3 sal
FROM emp order by sal desc
)
this will return the third highest sal of emp table
select max(column_name)
from table_name
where column_name not in ( select max(column_name)
from table_name
);
not in is a condition that exclude the highest value of column_name.
Reference : programmer interview
Something like this? I haven't tested it, though:
select top 1 x
from (
select top 2 distinct x
from y
order by x desc
) z
order by x
See How to select the nth row in a SQL database table?.
Sybase SQL Anywhere supports:
SELECT TOP 1 START AT 2 value from table ORDER BY value
Using a correlated query:
Select * from x x1 where 1 = (select count(*) from x where x1.a < a)
select * from emp e where 3>=(select count(distinct salary)
from emp where s.salary<=salary)
This query selects the maximum three salaries. If two emp get the same salary this does not affect the query.

Ensure that the correct number of rows are returned from a MySQL query

I have a (game) leaderboard table which contains a rank which is updated by another query. It is centered around the ID - when I query the table I ideally want to get back N records. So I have done a UNION on the records both with the limit N/2 like so:
(SELECT * FROM test1 t WHERE t.rank > (SELECT rank FROM test1 t2 WHERE id=ID)+0 ORDER BY rank LIMIT 0, N/2)
UNION ALL
(SELECT * FROM test1 t WHERE t.rank <= (SELECT rank FROM test1 t2 WHERE id=ID)+0 ORDER BY rank desc LIMIT 0, N/2) ORDER BY rank
Although this does not quite work when at the top of the leaderboard, it will only return the lower N/2. Is there a way to ensure that it will always return the N records? I did think that you could purposefully get more records than required and then trim the records off which you don't need. Although I do not know how to do this with a query!
Any help appreciated :)
You can do this with a clever use of order by and limit:
SELECT t.*
FROM test1 t cross join
(SELECT rank FROM test1 t2 WHERE id = #ID) as theone
ORDER BY ABS(theone.rank - t.rank)
LIMIT N;
You probably then want these back in rank order:
SELECT t.*
FROM (SELECT t.*
FROM test1 t cross join
(SELECT rank FROM test1 t2 WHERE id = #ID) as theone
ORDER BY ABS(theone.rank - t.rank)
LIMIT N
) t
ORDER BY t.rank;
Try with the following:
(SELECT * FROM test1 t WHERE t.rank > (SELECT rank FROM test1 t2 WHERE id=ID)+0 ORDER BY rank LIMIT 0,N)
UNION ALL
(SELECT * FROM test1 t WHERE t.rank <= (SELECT rank FROM test1 t2 WHERE id=ID)+0 ORDER BY rank desc LIMIT 0,N)
ORDER BY rank
LIMIT 0,N
See the manual for more insight.

Order mysql query in the same order I provide the OR statements in

Here's a query:
SELECT *
FROM table
WHERE id = 1
OR id = 100
OR id = 50
Note that I provided the ids in this order: 1,100,50.
I want the rows to come back in that order: 1,100,50.
Currently, i comes back 1,50,100 - basically in ascending order. Assume the rows in the table were inserted in ascending order also.
Use the MySQL specific FIND_IN_SET function:
SELECT t.*
FROM table t
WHERE t.id IN (1, 100, 50)
ORDER BY FIND_IN_SET(CAST(t.id AS VARCHAR(8)), '1,100,50')
Another way to approach this would put the list in a subquery:
select table.*
from table join
(select 1 as id, 1 as ordering union all
select 100 as id, 2 as ordering union all
select 50 as id, 3 as ordering
) list
on table.id = list.id
order by list.ordering
You can just do this with ORDER BY:
ORDER BY
id = 1 DESC, id = 100 DESC, id = 50 DESC
0 is before 1 in ORDER BY.
Try this
SELECT *
FROM new
WHERE ID =1
OR ID =100
OR ID =50
ORDER BY ID=1 DESC,ID=100 DESC,ID=50 DESC ;
http://www.sqlfiddle.com/#!2/796e2/5
... WHERE id IN (x,y,x) ORDER BY FIELD (id,x,y,z)