¿Cómo hago el top 1 en Oracle?

251

¿Cómo hago lo siguiente?

select top 1 Fname from MyTbl

En Oracle 11g ?

Oro
fuente
3
¿Puede decirnos el orden según el cual desea 'top 1'?
Andrew Wolfe
1
En primer lugar, nunca debe confiar en el motor DB para hacer eso. Si quieres saber cosas así, pon un secuenciador. Cuando lo haga, se garantiza que se numerarán en el orden en que se insertaron.
FlyingGuy
1
Material muy útil sobre este tema use-the-index-luke.com/sql/partial-results/top-n-queries
Ilia Maskov

Respuestas:

257

Si solo desea una primera fila seleccionada, puede:

select fname from MyTbl where rownum = 1

También puede usar funciones analíticas para ordenar y tomar la x superior:

select max(fname) over (rank() order by some_factor) from MyTbl
Mcpeterson
fuente
54
Esto es bueno si solo quieres 1 fila y no te importa cuál. Si desea filas específicas, como el registro más reciente, debe ordenarlas en una subselección, como la respuesta de Vash. Oracle asigna rownums antes del género.
Scott Bailey
44
@Scott sí. eso es correcto. Y Patrick, buen punto, creo que la sintaxis es incorrecta en eso. Realmente debería ser un aplazamiento (dense_rank () último ...)
mcpeterson
2
La diferencia entre el primer y el segundo ejemplo es que el primero selecciona una fila A (cualquier fila, sin orden). El segundo ejemplo obtiene el valor de la primera fila, sin hacer una consulta interna de orden (como en los ejemplos a continuación).
JulesLt
3
La sintaxis no es correcta en: seleccione max (fname) over (rank () ordenado por some_factor) de MyTbl
Stéphane Gerber el
1
@jclozano "no es una funcionalidad muy conocida de Oracle" - Con respeto, ruego diferir. Esto es importante porque la "funcionalidad no conocida" tiende a implicar oscuridad y, por lo tanto, podría sugerir que debemos evitar el uso. Esto no es oscuro, y no debe evitarse su uso.
Sepster
166
SELECT *
  FROM (SELECT * FROM MyTbl ORDER BY Fname )
 WHERE ROWNUM = 1;
Damian Leszczyński - Vash
fuente
8
Esta respuesta obtiene correctamente la fila SUPERIOR (ordena los resultados antes de restringir en ROWNUM).
JulesLt
Esta respuesta no es una traducción exacta: la consulta original no tiene ORDER BY ni devuelve todas las columnas de la tabla.
OMG Ponis
Estoy corregido (ver más abajo). Cambiará de votos una vez que se acabe el tiempo.
JulesLt
77
@OMGPonies sí. pero su probablemente lo que la mayoría de la gente realmente quiere que vienen a esta página mediante googlear su problema
NimChimpsky
44
Esta seguramente debe ser la respuesta ganadora en este hilo. Podría agregar una nota que, por top Xejemplo, puede cambiarlo aWHERE ROWNUM <= X
SomethingSomething, del
31

Con Oracle 12c (junio de 2013), puede usarlo de la siguiente manera.

SELECT * FROM   MYTABLE
--ORDER BY COLUMNNAME -OPTIONAL          
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
MSK
fuente
66
Comando interesante, estoy usando 12c aquí y OFFSET 0 ROWSaparentemente no es necesario, puedes usar FETCH NEXT 1 ROWS ONLYo incluso FETCH FIRST ROW ONLY, el orden por es importante o será equivalente a solo usar a WHERE rownum = 1. Incluso lo probé en una instrucción APLICACIÓN EXTERIOR y funcionó como la función TOP de Ms-SQL allí.
Rafael Merlin
Tienes razón @RafaelMerlin. Después de su publicación, reconocí que OFFSET 0 ROWS no es necesario. Sería útil al recuperar datos entre la parte superior X y la parte superior Y.
MSK
1
Más ejemplos: oracle-base.com/articles/12c/…
FixFaier
Hasta ahora todo bien, con un importante punto que falta TIES. Consulte esto para los casos en que se producen corbatas para la versión 12c +y12c -
Barbaros Özhan
10

Puede usar ROW_NUMBER()una ORDER BYcláusula en subconsulta y usar esta columna en reemplazo deTOP N . Esto se puede explicar paso a paso.

Vea la tabla a continuación que tiene dos columnas NAMEy DT_CREATED.

ingrese la descripción de la imagen aquí

Si necesita tomar solo las dos primeras fechas independientemente de NAME, puede usar la consulta a continuación. La lógica ha sido escrita dentro de la 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

ingrese la descripción de la imagen aquí

En algunas situaciones, necesitamos seleccionar TOP Nresultados respectivos a cada uno NAME. En tal caso, podemos usar PARTITION BYcon una ORDER BYcláusula en subconsulta. Consulte la consulta a continuación.

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

ingrese la descripción de la imagen aquí

Sarath Avanavu
fuente
1
Usar ROW_NUMBER () ... es una solución más correcta que en la respuesta al tema. Un problema con esta solución (y con la variante max (field) también) es que no puede hacer cosas como "seleccionar ... (seleccione ROW_NUMBER () ...) para actualizar ";
Alexo Po.
Y a veces es muy importante en PL / SQL (lo siento, no se pudo editar el comentario anterior en el límite de 5 minutos).
Alexo Po.
En tal caso, podemos usar CTE como en la parte exterior. ¿Correcto? @Alexo Po.
Sarath Avanavu
Creo que no te entiendo. para la cláusula de actualización se puede utilizar cuando Oracle preserva "ROWID" fácilmente. Por lo tanto, la agrupación (y la agrupación debido al uso de la cláusula analítica) oculta el ROWID real y las filas no se pueden bloquear. Y segundo, CTE ( with (select ... ) as cláusula) no cambia nada a este problema, CTE solo tiene como objetivo leer y respaldar consultas. ¿Correcto? @Sarath Avanavu
Alexo Po.
Nota sobre mi mismo. El problema con ROWID en realidad ocurre específicamente porque la condición RNO <3 , en este caso, el valor de RNO no está conectado con ROWID, por lo que Oracle no puede bloquear filas.
Alexo Po.
9

Puedes hacer algo como

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

También puedes usar las funciones analíticas RANK y / o DENSE_RANK , pero ROWNUM es probablemente la más fácil.

Suman
fuente
1
¿Pueden ayudarme con algún ejemplo de rango, etc.?
breakfreehg
9
select * from (
    select FName from MyTbl
)
where rownum <= 1;
Arkansas
fuente
5

Utilizar:

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

Si usa Oracle9i +, podría usar funciones analíticas como ROW_NUMBER () pero no funcionarán tan bien como ROWNUM .

Ponis OMG
fuente
1
Buena respuesta pero contiene un pequeño error tipográfico. ¿Dónde dices Oracle9i + no debería ser 8i? download-west.oracle.com/docs/cd/A87860_01/doc/server.817/…
Ian Carpenter
@carpenteri: Es cierto, los análisis estaban disponibles en 8i, no puedo recordar los detalles, pero los análisis no estaban realmente disponibles para el público hasta el 9i.
OMG Ponis
Pequeño comentario: la respuesta de Vash a continuación incluye un ORDER BY en la consulta interna que es fundamental si desea el valor TOP de fname, en lugar de 'first' (que puede ser cualquier cosa, probablemente la primera fila insertada). ¿Podría valer la pena una edición?
JulesLt
@JulesLt: la consulta proporcionada por el OP no incluye un ORDER BY, por lo que esta es la respuesta representa y la traducción exacta a la sintaxis de Oracle.
OMG Ponis
Mi malentendido de la sintaxis de SQL SERVER TOP (supuse erróneamente que era similar a FIRST in RANK, no ROWNUM). Votado
JulesLt
3

Seleccionar la primera fila de una tabla y seleccionar una fila de una tabla son dos tareas diferentes y necesitan una consulta diferente. Hay muchas formas posibles de hacerlo. Cuatro de ellos son:

primero

select  max(Fname) from MyTbl;

Segundo

select  min(Fname) from MyTbl;

Tercero

select  Fname from MyTbl  where rownum = 1;

Cuarto

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

Tuve el mismo problema y puedo solucionarlo con esta solución:

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

Puede ordenar su resultado antes para tener el primer valor en la parte superior.

Buena suerte

user2607028
fuente