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.
I have a table with 3 columns (id, name, code) and 10 rows. Some of the rows don't have a code so that column is empty for some. What I'm trying to accomplish is SELECT the rows with code column not empty first ordered by last inserted followed by all rows with code column empty ordered by last inserted.
I have tried
(SELECT * from tablename WHERE code <> '' ORDER BY ID DESC) UNION
(SELECT * from tablename WHERE code = '' ORDER BY ID DESC)
The UNION works but the order does not. I have read here about other questions and found out adding ORDER BY like I added will not work and I should add it at the end but that would not help me accomplish what I want and will mix rows that have a code with rows that don't.
Is there a way to succeed with what I'm looking for?
I think you just need to put your sort logic in the ORDER BY clause
SELECT id, name, code
FROM tablename
ORDER BY code = '', ID desc;
Try this:
SELECT * FROM
(
(SELECT * from tablename WHERE code <> '' ORDER BY ID DESC)
UNION
(SELECT * from tablename WHERE code = '' ORDER BY ID DESC)
)tab ORDER BY ID DESC;
Or
SELECT * from tablename ORDER BY code DESC,ID DESC
Change ASC/DESC as per you want it to show
Lets say I have a MySQL table that has the following entries:
1
2
3
2
5
6
7
6
6
8
When I do an "SELECT * ..." I get back all the entries. But I want to get back only these entries, that exist only once within the table. Means the rows with the values 2 (exists two times) and 6 (exists three times) have to be dropped completely out of my result.
I found a keyword DISTINCT but as far as I understood it only avoids entries are shown twice, it does not filters them completely.
I think it can be done somehow with COUNT, but all I tried was not really successful. So what is the correct SQL statement here?
Edit: to clarify that, the result I want to get back is
1
3
5
7
8
You can use COUNT() in combination with a GROUP BY and a HAVING clause like this:
SELECT yourCol
FROM yourTable
GROUP BY yourCol
HAVING COUNT(*) < 2
Example fiddle.
You want to mix GROUP BY and COUNT().
Assuming the column is called 'id' and the table is called 'table', the following statement will work:
SELECT * FROM `table` GROUP BY id HAVING COUNT(id) = 1
This will filter out duplicate results entirely (e.g. it'll take out your 2's and 6's)
Three ways. One with GROUP BY and HAVING:
SELECT columnX
FROM tableX
GROUP BY columnX
HAVING COUNT(*) = 1 ;
one with a correlated NOT EXISTS subquery:
SELECT columnX
FROM tableX AS t
WHERE NOT EXISTS
( SELECT *
FROM tableX AS t2
WHERE t2.columnX = t.columnX
AND t2.pk <> t.pk -- pk is the primary key of the table
) ;
and an improvement on the first way (if you have a primary key pk column and an index on (columnX, pk):
SELECT columnX
FROM tableX
GROUP BY columnX
HAVING MIN(pk) = MAX(pk) ;
select id from foo group by id having count(*) < 2;
I have a table and I only display the latest 30 rows by order by ID.
I'm trying to delete any rows after the 30 newest rows by using this query below.
DELETE FROM table WHERE type = 'test' ORDER BY id DESC LIMIT 30, 60
I keep getting this error below
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' 60' at line 1
What am I doing wrong?
Try this one,
DELETE FROM table
WHERE ID IN
(
SELECT ID
FROM
(
SELECT ID
FROM table
WHERE Type = 'TEST'
ORDER BY ID
LIMIT 30,60
) a
)
Second edit: While MySQL supports LIMIT in delete statements, it does not allow an OFFSET. This means that you cannot skip the first 30 rows.
Make a subselect on id (or any other primary key):
DELETE FROM table WHERE id IN (SELECT id FROM table WHERE type = 'test' ORDER BY id DESC LIMIT 30, 60)
This is not possible this way.
You could try it with a nested select statement, somewhat like this:
DELETE FROM table
WHERE type = 'test'
AND ID IN (SELECT id from table where type = 'test' order by id desc limit 30 )
Try like this
DELETE FROM table WHERE id in(SELECT id FROM table WHERE type = "test" order by id desc limit 30, 60)
I was unable to use the limit clause in the sub-query, so the solution I use, somewhat messy, is:-
select group_concat(id) into #idList from
(
select id from table order by id desc limit 0,30
) as saveIds;
delete from table where not find_in_set(id,#idList)
Alternatively,
select group_concat(id) into #idList from
(
select id from table order by id desc limit 30
) as saveIds;
delete from table where find_in_set(id,#idList)
SELECT id FROM table LIMIT 8, 3
results in 8,9,10
but I need 10,9,8
How can you do this? If you add "ORDER BY id DESC" it gets 3,2,1
Put your query in a subselect and then reverse the order in the outer select:
SELECT id from (
SELECT id FROM table ORDER BY id LIMIT 8, 3
) AS T1 ORDER BY id DESC
Test data:
CREATE TABLE table1 (id INT NOT NULL);
INSERT INTO table1 (id) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
SELECT id from (
SELECT id FROM table1 ORDER BY id LIMIT 8, 3
) AS T1 ORDER BY id DESC
Result:
10
9
8
Note that the ORDER BY in the subquery is required otherwise the order is undefined. Thanks to Lasse for pointing this out!
First of all, if you're not ordering at all, that you got 8,9,10 right now might be related to the index used. Are you sure this isn't going to change in the future?
What I'm getting at is that unless you specify an order, you should not rely on it being the one you want.
So I would definitely add an order to that select to specify what you want. Otherwise you're only saying "give me 3 numbers from this table", not "give me 3 numbers from this table according to these rules". Why is 3,2,1 wrong but 8,9,10 right? You're not specifying.
Anyway, to answer your question, you must order after the limit, which means a subselect:
SELECT id FROM (
SELECT id FROM table LIMIT 8, 3
) AS dummy ORDER BY id DESC
However, I would try this SQL instead, related to the part about specifying:
SELECT id FROM (
SELECT id FROM table ORDER BY id LIMIT 8, 3
) AS dummy ORDER BY id DESC