Qual é a consulta SQL mais simples para encontrar o segundo maior valor?

168

Qual é a consulta SQL mais simples para encontrar o segundo maior valor inteiro em uma coluna específica?

Talvez haja valores duplicados na coluna.

Niyaz
fonte
. utilizar offset para este purpos ... Selecione extensão de [dbo] [Empregados] ordem por extensão desc compensado 2 linhas buscar próximas linhas 1 única
Jinto John

Respostas:

294
SELECT MAX( col )
  FROM table
 WHERE col < ( SELECT MAX( col )
                 FROM table )
Matt Rogish
fonte
7
A resposta de Matt e Vinoy também cuida de duplicatas. Suponha que o maior valor seja repetido e, em seguida, usar a resposta de Matt produzirá o segundo maior valor correto, enquanto se você usou a abordagem 2 desc e min , poderá obter o maior valor.
Pankaj Sharma
E se houver vários segundos mais altos ... Então isso não dará todas as Tuplas
Parth Satra
2
obrigado, usou isso para encontrar penúltima data aqui
shaijut
Muito melhor do que a minha abordagem usando ORDER_BY e LIMIT para a instrução interior
andig
Observe que isso não retornará um resultado se não houver registros antes do solicitado.
andig
61
SELECT MAX(col) FROM table WHERE col NOT IN (SELECT MAX(col) FROM table);
Vinoy
fonte
31

No T-Sql, existem duas maneiras:

--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 

No Microsoft SQL, a primeira maneira é duas vezes mais rápida que a segunda, mesmo se a coluna em questão estiver em cluster.

Isso ocorre porque a operação de classificação é relativamente lenta em comparação com a tabela ou a varredura de índice que a maxagregação usa.

Como alternativa, no Microsoft SQL 2005 e acima, você pode usar a ROW_NUMBER()função:

select col
from (
    select ROW_NUMBER() over (order by col asc) as 'rowNum', col
    from [table] ) withRowNum 
where rowNum = 2
Keith
fonte
20

Vejo aqui algumas soluções específicas do SQL Server e algumas específicas do MySQL, portanto, você pode esclarecer qual banco de dados precisa. Embora, se eu tivesse que adivinhar, diria o SQL Server, pois isso é trivial no MySQL.

Também vejo algumas soluções que não funcionam porque não levam em consideração a possibilidade de duplicatas; portanto, tome cuidado com as que você aceita. Por fim, vejo alguns que funcionarão, mas que farão duas varreduras completas da tabela. Você deseja garantir que a 2ª varredura esteja apenas com 2 valores.

SQL Server (antes de 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

Atualizar:

O SQL Server 2012 agora oferece suporte a uma sintaxe OFFSET / FETCH muito mais limpa (e padrão ):

SELECT TOP 2 [column] 
FROM [Table] 
GROUP BY [column] 
ORDER BY [column] DESC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY;
Joel Coehoorn
fonte
Era isso que eu esperava ver. A resposta aceita fica feia se você precisar trabalhar para alguma n. Este é aquele teste.
9788 Robin Maben
@RobinMaben Robin, que tal o cenário em que o maior valor é repetido? Suponha que uma coluna contenha os números de 1 a 100, mas 100 seja repetido duas vezes. Em seguida, esta solução produzirá o segundo maior valor como 100, o que estará incorreto. Certo?
Pankaj Sharma
1
@PankajSharma não, este trabalho ainda, por causa da cláusula GROUP BY
Joel Coehoorn
Esta é a maneira padrão de fazer isso. A resposta aceita deve ser atualizada para esta.
Guilherme Melo
1
Eu recebo um erro que diz que não posso usar TOPe OFFSETna mesma consulta.
Spurious
15

Suponho que você possa fazer algo como:

SELECT * FROM Table ORDER BY NumericalColumn DESC LIMIT 1 OFFSET 1

ou

SELECT * FROM Table ORDER BY NumericalColumn DESC LIMIT (1, 1)

dependendo do seu servidor de banco de dados. Dica: o SQL Server não executa LIMIT.

dguaraglia
fonte
update- O SQL Server 2012 adicionou uma cláusula de deslocamento / busca semelhante à dbadiaries.com/…
iliketocode
Suponha que você tenha 2 elementos com o mesmo valor, mas também o maior elemento. Eu acho que você tem que fazerOFFSET 2
Kangkan
A adição da cláusula GROUP BY atenderá à condição duplicada.
Saif
7

O mais fácil seria obter o segundo valor desse conjunto de resultados no aplicativo:

SELECT DISTINCT value FROM Table ORDER BY value DESC LIMIT 2

Mas se você deve selecionar o segundo valor usando SQL, que tal:

SELECT MIN(value) FROM (SELECT DISTINCT value FROM Table ORDER BY value DESC LIMIT 2) AS t
Magnar
fonte
1
Você já executou isso no SQL Server?
Craig
1
@ Craig - LIMITé a sintaxe MySql, a questão não especifica uma versão SQL.
Keith
4

Uma consulta muito simples para encontrar o segundo maior valor

SELECT `Column` FROM `Table` ORDER BY `Column` DESC LIMIT 1,1;
mesquinho
fonte
4

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

Não há necessidade de subconsultas ... basta pular uma linha e selecionar as segundas linhas após o pedido, descendo

Justin Jose
fonte
3
SELECT MAX(Salary) FROM Employee WHERE Salary NOT IN (SELECT MAX(Salary) FROM Employee )

Esta consulta retornará o salário máximo, do resultado - que não contém o salário máximo da tabela geral.

Naresh Kumar
fonte
2
Você pode editar para explicar como isso é significativamente diferente das respostas antigas?
Nathan Tuggy
3

Velha pergunta eu sei, mas isso me deu um plano executivo melhor:

 SELECT TOP 1 LEAD(MAX (column)) OVER (ORDER BY column desc)
 FROM TABLE 
 GROUP BY column
dier
fonte
3

Este é um código muito simples, você pode tentar o seguinte: -

ex: nome da tabela = teste

salary 

1000
1500
1450
7500

Código MSSQL para obter o segundo maior valor

select salary from test order by salary desc offset 1 rows fetch next 1 rows only;

aqui 'deslocamento de 1 linha' significa a segunda linha da tabela e 'buscar apenas as 1 linhas seguintes' serve apenas para mostrar essa 1 linha. se você não usar 'buscar somente as próximas 1 linhas', mostrará todas as linhas da segunda linha.

Nijish.
fonte
Resposta mais otimizada e favorável aos recursos. Economizei bastante tempo usando-o na minha subconsulta. Obrigado.
vibs2006
2

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

Espero que esta ajuda obtenha o valor para qualquer linha .....

Rohit Singh
fonte
2

Mais simples de tudo

select sal from salary order by sal desc limit 1 offset 1
sumeet
fonte
1
select min(sal) from emp where sal in 
    (select TOP 2 (sal) from emp order by sal desc)

Nota

sal é nome da coluna
emp é nome da tabela

Ni3
fonte
1

Tom, acredite que isso falhará quando houver mais de um valor retornado na select max([COLUMN_NAME]) from [TABLE_NAME]seção. ou seja, onde existem mais de 2 valores no conjunto de dados.

Uma pequena modificação na sua consulta funcionará -

select max([COLUMN_NAME]) from [TABLE_NAME] where [COLUMN_NAME] **IN** 
  ( select max([COLUMN_NAME]) from [TABLE_NAME] )
sunith
fonte
1
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));

subconsulta retorna todos os valores que não sejam os maiores. selecione o valor máximo na lista retornada.

sunith
fonte
1
select col_name
from (
    select dense_rank() over (order by col_name desc) as 'rank', col_name
    from table_name ) withrank 
where rank = 2
Divya.NR
fonte
1
SELECT 
    * 
FROM 
    table 
WHERE 
    column < (SELECT max(columnq) FROM table) 
ORDER BY 
    column DESC LIMIT 1
pardais avie
fonte
1

É a maneira mais esiest:

SELECT
      Column name
FROM
      Table name 
ORDER BY 
      Column name DESC
LIMIT 1,1
Ravind Maurya
fonte
1
select age from student group by id having age<(select max(age) from student)order by age limit 1
IMPASSE
fonte
1

Como você mencionou valores duplicados. Nesse caso, você pode usar DISTINCT e GROUP BY para descobrir o segundo valor mais alto

Aqui está uma mesa

salário

:

insira a descrição da imagem aqui

GRUPO POR

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

Primeira parte de LIMIT = índice inicial

Segunda parte de LIMIT = quanto valor

Shourob Datta
fonte
1
SELECT MAX(sal) FROM emp
WHERE sal NOT IN (SELECT top 3 sal FROM emp order by sal desc )

isso retornará o terceiro maior sal da tabela emp

Swadesh
fonte
1
select max(column_name) from table_name
where column_name not in (select max(column_name) from table_name);

not in é uma condição que exclui o valor mais alto de column_name.

Referência: entrevista do programador

rashedcs
fonte
0

Algo assim? Eu ainda não testei:

select top 1 x
from (
  select top 2 distinct x 
  from y 
  order by x desc
) z
order by x
doekman
fonte
0

Usando uma consulta correlacionada:

Select * from x x1 where 1 = (select count(*) from x where x1.a < a)
sth
fonte
0
select * from emp e where 3>=(select count(distinct salary)
    from emp where s.salary<=salary)

Esta consulta seleciona o máximo de três salários. Se dois emp recebem o mesmo salário, isso não afeta a consulta.

sth
fonte
0
select top 1 MyIntColumn from MyTable
where
 MyIntColumn <> (select top 1 MyIntColumn from MyTable order by MyIntColumn desc)
order by MyIntColumn desc
Chris Conway
fonte
0

Isso funciona no MS SQL:

select max([COLUMN_NAME]) from [TABLE_NAME] where [COLUMN_NAME] < 
 ( select max([COLUMN_NAME]) from [TABLE_NAME] )
Tom Welch
fonte