Como eu faço o top 1 no Oracle?

251

Como faço o seguinte?

select top 1 Fname from MyTbl

No Oracle 11g ?

Ouro
fonte
3
Você pode nos dizer a ordem de acordo com a qual deseja 'top 1'?
Andrew Wolfe
1
Antes de tudo, você nunca deve confiar no mecanismo de banco de dados para fazer isso. Se você quiser saber coisas assim, coloque um seqüenciador. Quando você faz isso, é garantido que eles serão numerados na ordem em que foram inseridos.
precisa saber é o seguinte
1
Material muito usful sobre este tema use-the-index-luke.com/sql/partial-results/top-n-queries
Ilia Maskov

Respostas:

257

Se você quiser apenas uma primeira linha selecionada, poderá:

select fname from MyTbl where rownum = 1

Você também pode usar funções analíticas para solicitar e obter as principais x:

select max(fname) over (rank() order by some_factor) from MyTbl
Mcpeterson
fonte
54
Isso é bom se você quer apenas 1 linha e não se importa com qual. Se você quiser linhas específicas, como o registro mais recente, precisará fazer a classificação em uma subseleção, como a resposta de Vash. O Oracle atribui rownums antes da classificação.
Scott Bailey
4
@Scott yup. está correto. E Patrick, bom ponto, acho que a sintaxe está incorreta nisso. Realmente deve ser uma fortaleza over (DENSE_RANK () última ...)
mcpeterson
2
A diferença entre o primeiro e o segundo exemplo é que o primeiro seleciona uma linha (qualquer linha, sem ordem). O segundo exemplo obtém o valor da primeira linha, sem fazer uma consulta interna da ordem (como nos exemplos abaixo).
precisa saber é o seguinte
3
A sintaxe em não correto em: (ordem de classificação () por some_factor) select max (fname) ao longo de MyTbl
Stéphane Gerber
1
@jclozano "não é uma funcionalidade muito conhecida do oracle" - Com respeito, eu imploro para diferir. Isso importa porque "funcionalidade não conhecida" tende a implicar obscuridade e, portanto, pode sugerir que devemos evitar o uso. Isso não é obscuro e seu uso não deve ser evitado.
Sepster 18/03/2015
166
SELECT *
  FROM (SELECT * FROM MyTbl ORDER BY Fname )
 WHERE ROWNUM = 1;
Damian Leszczyński - Vash
fonte
8
Esta resposta obtém corretamente a linha TOP (ordena os resultados antes de restringir o ROWNUM).
precisa saber é o seguinte
Esta resposta não é uma tradução exata - a consulta original não possui um ORDER BY, nem retorna todas as colunas da tabela.
OMG Ponies
Eu estou corrigido (veja abaixo). Mudará votos assim que o tempo acabar.
precisa saber é o seguinte
7
@OMGPonies yeah. mas o seu provavelmente o que a maioria das pessoas realmente querem que vêm a esta página através de pesquisar o seu problema
Nim Chimpsky
4
Esta com certeza deve ser a resposta vencedora neste tópico. Eu poderia acrescentar uma nota que, para top Xalguém pode alterá-lo paraWHERE ROWNUM <= X
SomethingSomething
31

Com o Oracle 12c (junho de 2013), você pode usá-lo da seguinte maneira.

SELECT * FROM   MYTABLE
--ORDER BY COLUMNNAME -OPTIONAL          
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
MSK
fonte
6
Comando interessante, estou usando 12c aqui e, OFFSET 0 ROWSaparentemente, não é necessário, você pode usar FETCH NEXT 1 ROWS ONLYou até mesmo FETCH FIRST ROW ONLY, a ordem por é importante ou será equivalente a apenas usar a WHERE rownum = 1. Eu até tentei em uma instrução OUTER APPLY e funcionou como a função TOP do Ms-SQL lá.
Rafael Merlin
Você está certo @RafaelMerlin. Após sua postagem, reconheci que OFFSET 0 ROWS não é necessário. Seria útil ao recuperar dados entre os principais X e Y.
MSK
1
Mais exemplos: oracle-base.com/articles/12c/…
FixFaier
Até aí tudo bem, com um importante ponto que falta TIES. Consulte este para os casos em que os laços ocorrer por versão 12c +e12c -
Barbaros Özhan
10

Você pode usar ROW_NUMBER()com uma ORDER BYcláusula na subconsulta e usar esta coluna em substituição de TOP N. Isso pode ser explicado passo a passo.

Veja a tabela abaixo que possui duas colunas NAMEe DT_CREATED.

insira a descrição da imagem aqui

Se você precisar fazer apenas as duas primeiras datas, independentemente NAME, poderá usar a consulta abaixo. A lógica foi escrita dentro da consulta

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
    -- Generates numbers in a column in sequence in the order of date
    SELECT ROW_NUMBER() OVER (ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

RESULTADO

insira a descrição da imagem aqui

Em algumas situações, precisamos selecionar os TOP Nresultados respectivos para cada um NAME. Nesse caso, podemos usar PARTITION BYcom uma ORDER BYcláusula na subconsulta. Consulte a consulta abaixo.

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
  --Generates numbers in a column in sequence in the order of date for each NAME
    SELECT ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

RESULTADO

insira a descrição da imagem aqui

Sarath Avanavu
fonte
1
Usar ROW_NUMBER () ... é a solução mais correta do que na resposta do tópico. Um problema com esta solução (e com a variante max (field) também) em que você não pode fazer coisas como "selecionar ... (selecione ROW_NUMBER () ...) para atualização ;"
Alexo Po.
E às vezes é muito importante no PL / SQL (desculpe, não foi possível editar o comentário anterior no limite de 5 minutos).
Alexo Po.
Nesse caso, podemos usar CTE como na parte externa. Certo? @Alexo Po.
Sarath Avanavu
Eu acho que não te entendo. A cláusula for update pode ser usada quando o ROWID é "facilmente" preservado pelo Oracle. Portanto, o agrupamento (e o agrupamento devido ao uso da cláusula analítica) oculta o ROWID real e as linhas não podem ser bloqueadas. E segundo, a CTE ( with (select ... ) as cláusula) não altera nada para esse problema, a CTE visa apenas ler e dar suporte a consultas. Certo? @Sarath Avanavu
Alexo Po.
Nota em mim mesmo. O problema com o ROWID realmente acontece especificamente por causa da condição RNO <3 , neste caso, o valor do RNO não está conectado ao ROWID, e é por isso que o Oracle não pode bloquear linhas.
Alexo Po.
9

Você pode fazer algo como

    SELECT *
      FROM (SELECT Fname FROM MyTbl ORDER BY Fname )
 WHERE rownum = 1;

Você também pode usar as funções analíticas RANK e / ou DENSE_RANK , mas ROWNUM é provavelmente o mais fácil.

Suman
fonte
1
você pode por favor me ajude com algum exemplo de classificação etc.
breakfreehg
9
select * from (
    select FName from MyTbl
)
where rownum <= 1;
a'r
fonte
5

Usar:

SELECT x.*
  FROM (SELECT fname 
          FROM MyTbl) x
 WHERE ROWNUM = 1

Se estiver usando o Oracle9i +, você pode usar funções analíticas como ROW_NUMBER (), mas elas não terão um desempenho tão bom quanto o ROWNUM .

Pôneis OMG
fonte
1
Boa resposta, mas contém um pequeno erro de digitação. Onde você diz que o Oracle9i + não deveria ser o 8i? download-west.oracle.com/docs/cd/A87860_01/doc/server.817/...
Ian Carpenter
@carpenteri: É verdade que a análise estava disponível no 8i - não consigo lembrar os detalhes, mas a análise não estava realmente disponível ao público até o 9i.
OMG Ponies
Pequeno comentário - a resposta de Vash abaixo inclui uma ORDER BY na consulta interna, que é crítica se você deseja o valor TOP de fname, em vez de 'first' (que pode ser qualquer coisa, provavelmente a primeira linha inserida). Vale a pena editar?
precisa saber é o seguinte
@JulesLt: a consulta fornecida pelo OP não inclui um ORDER BY, portanto, esta é a resposta e representa a tradução exata para a sintaxe do Oracle.
OMG Ponies
Meu mal-entendido da sintaxe SQL SERVER TOP (erroneamente presumiu-se que era semelhante ao PRIMEIRO em RANK, não em ROWNUM). Votado.
precisa saber é o seguinte
3

Para selecionar a primeira linha de uma tabela e selecionar uma linha de uma tabela, são duas tarefas diferentes e precisam de uma consulta diferente. Existem muitas maneiras possíveis de fazer isso. Quatro deles são:

Primeiro

select  max(Fname) from MyTbl;

Segundo

select  min(Fname) from MyTbl;

Terceiro

select  Fname from MyTbl  where rownum = 1;

Quarto

select  max(Fname) from MyTbl where rowid=(select  max(rowid) from MyTbl)
Vikas Hardia
fonte
3

Eu tive o mesmo problema e posso corrigir isso com esta solução:

select a.*, rownum 
from (select Fname from MyTbl order by Fname DESC) a
where
rownum = 1

Você pode solicitar seu resultado antes para ter o primeiro valor no topo.

Boa sorte

user2607028
fonte