¿Cómo seleccionar la fila n en una tabla de base de datos SQL?

Estoy interesado en aprender algunas (idealmente) formas independientes de la base de datos de seleccionar el nla fila de una tabla de base de datos. También sería interesante ver cómo se puede lograr esto utilizando la funcionalidad nativa de las siguientes bases de datos:

  • SQL Server
  • MySQL
  • PostgreSQL
  • SQLite
  • Oracle

Actualmente estoy haciendo algo como lo siguiente en SQL Server 2005, pero me interesaría ver los enfoques más agnósticos de otros:

WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000

Crédito por el SQL anterior: Weblog de Firoz Ansari

Actualizar: Vea La respuesta de Troels Arvin con respecto al estándar SQL. Troels, ¿tienes algún enlace que podamos citar?

preguntado el 19 de agosto de 08 a las 15:08

Si. Aquí hay un enlace a información sobre el estándar ISO SQL: troels.arvin.dk/db/rdbms/links/#standards -

Solo para señalar que, según la definición de una relación, las filas de una tabla no tienen orden, por lo que la fila N-ésima de una tabla no se puede seleccionar. Lo que se puede seleccionar es la fila N en un conjunto de filas devuelto por (el resto de) una consulta, que es lo que logran su ejemplo y todas las demás respuestas. Para la mayoría, esto puede ser solo semántica, pero apunta al problema subyacente de la pregunta. Si necesita regresar OrderNo N , luego introduce un OrderSequenceNo columna de la tabla y generarla a partir de una generador de secuencia independiente al crear un nuevo orden. -

El estándar SQL define la opción offset x fetch first y rows only. Actualmente es compatible con (al menos) Postgres, Oracle12, DB2. -

30 Respuestas

Hay formas de hacer esto en partes opcionales del estándar, pero muchas bases de datos admiten su propia forma de hacerlo.

Un sitio realmente bueno que habla sobre esto y otras cosas es http://troels.arvin.dk/db/rdbms/#select-limit.

Básicamente, PostgreSQL y MySQL admiten lo no estándar:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 y MSSQL admiten las funciones estándar de ventanas:

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber <= n

(que acabo de copiar del sitio vinculado anteriormente ya que nunca uso esas bases de datos)

Actualizar: A partir de PostgreSQL 8.4, las funciones de ventanas estándar son compatibles, así que espere que el segundo ejemplo funcione también para PostgreSQL.

Actualizar: SQLite agregó compatibilidad con funciones de ventana en la versión 3.25.0 el 2018-09-15, por lo que ambas formas también funcionan en SQLite.

Respondido 27 Feb 19, 15:02

MySQL también usa la sintaxis OFFSET y LIMIT. Firebird usa las palabras clave FIRST y SKIP, pero se colocan justo después de SELECT. - Doug

¿No debería ser eso? WHERE rownumber = n para obtener solo la enésima fila? - Steve Bennett

MySQL admite funciones de ventana desde la versión 8. MariaDB desde la versión 10.2 - Pablo Spiegel

Soporta PostgreSQL funciones de ventana como lo define el estándar SQL, pero son incómodos, por lo que la mayoría de la gente usa (el no estándar) LIMIT / OFFSET:

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;

Este ejemplo selecciona la fila 21. OFFSET 20 le está diciendo a Postgres que omita los primeros 20 registros. Si no especifica un ORDER BY cláusula, no hay garantía de qué registro recuperará, lo que rara vez es útil.

Respondido 16 Oct 19, 14:10

No estoy seguro del resto, pero sé que SQLite y MySQL no tienen ningún orden de filas "predeterminado". En esos dos dialectos, al menos, el siguiente fragmento toma la entrada número 15 de the_table, ordenando por la fecha / hora en que se agregó:

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15

(por supuesto, necesitaría tener un campo DATETIME agregado y establecerlo en la fecha / hora en que se agregó la entrada ...)

Respondido 19 ago 08, 18:08

Esta parece la mejor manera de limitar la consulta con el valor de compensación en línea. ¿Pero no deberíamos usar 0,14 aquí? 1,15 dejará la primera fila. - Gladiator

Sin embargo, ¿qué significa el 15? Sé que el 1 dice que consiga un registro. La coma no se usa en el ejemplo que revisé 1keydata.com/sql/sql-limit.html - comprometido

En realidad, desde aqui php.about.com/od/mysqlcommands/g/Limit_sql.htm, si quisiera tomar la entrada número 15, ¿no haría LIMIT 14, 1 (0th es el primer elemento, 1 de longitud - comprometido

debe ser SELECCIONADO * DE la_tabla ORDENAR POR LÍMITE DE DESC agregado 15,1 - GorvGoyl

SQL 2005 y versiones posteriores tienen esta función incorporada. Utilice la función ROW_NUMBER (). Es excelente para páginas web con un estilo de navegación << Anterior y Siguiente >>:

Sintaxis:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

Respondido el 14 de diciembre de 16 a las 10:12

Prefiero esta solución, ya que se siente más sencilla. - ZorroArco

Sospecho que esto es tremendamente ineficiente, pero es un enfoque bastante simple, que funcionó en un pequeño conjunto de datos en el que lo probé.

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

Esto obtendría el quinto elemento, cambiaría el segundo número superior para obtener un n-ésimo elemento diferente

Solo servidor SQL (creo), pero debería funcionar en versiones anteriores que no admiten ROW_NUMBER ().

Respondido 19 ago 08, 18:08

Voy a usar esto ya que ROW_NUMBER () no funciona en SQL 2000 (sí, todavía tenemos un cliente en SQL 2000) Específicamente, reemplazaré el '5' con una variable iteradora de un bucle y usaré que copiar y modificar cada fila de una tabla a su vez. Tal vez alguien vea este comentario y lo encuentre útil: Inverso

Verifíquelo en SQL Server:

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp

¡Esto le dará la 10ª FILA de la tabla emp!

Respondido 09 Abr '15, 21:04

Ya proporcionaste una respuesta a esta pregunta aquí Elimine la respuesta que crea que no es correcta. Si cree que ambas respuestas son correctas, publique ambas respuestas en un solo lugar: SpringLearner

1 cambio pequeño: n-1 en lugar de n.

select *
from thetable
limit n-1, 1

Respondido el 03 de diciembre de 12 a las 23:12

que tecnologia - user230910

Al contrario de lo que afirman algunas de las respuestas, el estándar SQL no guarda silencio con respecto a este tema.

Desde SQL: 2003, ha podido utilizar "funciones de ventana" para omitir filas y limitar conjuntos de resultados.

Y en SQL: 2008, se agregó un enfoque un poco más simple, utilizando
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

Personalmente, no creo que la adición de SQL: 2008 fuera realmente necesaria, así que si yo fuera ISO, lo habría mantenido fuera de un estándar ya bastante grande.

Respondido el 20 de Septiembre de 17 a las 20:09

Sin embargo, es bueno que haya un estándar, hace que la vida de personas como yo sea más fácil, y es tan agradable que Microsoft haga las cosas de manera estándar :) user230910

SERVIDOR SQL


Seleccione el registro n de la parte superior

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

seleccione el registro n de la parte inferior

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

Respondido 19 Feb 14, 04:02

Cuando solíamos trabajar en MSSQL 2000, hicimos lo que llamamos el "triple flip":

EDITADO

DECLARE @InnerPageSize int
DECLARE @OuterPageSize int
DECLARE @Count int

SELECT @Count = COUNT(<column>) FROM <TABLE>
SET @InnerPageSize = @PageNum * @PageSize
SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize)

IF (@OuterPageSize < 0)
    SET @OuterPageSize = 0
ELSE IF (@OuterPageSize > @PageSize)
    SET @OuterPageSize = @PageSize

DECLARE @sql NVARCHAR(8000)

SET @sql = 'SELECT * FROM
(
    SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM
    (
        SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC
    ) AS t1 ORDER BY <column> DESC
) AS t2 ORDER BY <column> ASC'

PRINT @sql
EXECUTE sp_executesql @sql

No fue elegante ni rápido, pero funcionó.

Respondido el 30 de diciembre de 11 a las 15:12

Supongamos que tiene 25 filas y desea la tercera página de tamaño de página de 10 filas, es decir, las filas 21-25. La consulta más interna obtiene las 30 filas superiores (filas 1-25). La consulta del medio obtiene las últimas 10 filas (filas 25-16). La consulta externa los reordena y devuelve las filas 16-25. Esto es claramente incorrecto si desea las filas 21-25. - Bill Karwin

Ahora no funciona si queremos una página intermedia. Digamos que tenemos 25 filas y queremos la segunda página, es decir, las filas 11-20. La consulta interna obtiene los primeros 2 * 10 = 20 filas, o filas 1-20. La consulta del medio obtiene las últimas 15 filas: 25 - ((2-1) * 10) = 15, lo que produce las filas 20-6. La última consulta invierte el orden y devuelve las filas 6-20. Esta técnica no funciona, a menos que el número total de filas sea un múltiplo del tamaño de página deseado. - Bill Karwin

Quizás la mejor conclusión es que deberíamos actualizar las instancias restantes de MS SQL Server 2000. :-) ¡Es casi el 2012, y este problema se ha resuelto de mejor manera durante muchos años! - Bill Karwin

@Bill Karwin: Tenga en cuenta el IF / ELSE IF bloques debajo del OuterPageSize cálculo: en las páginas 1 y 2, dejarán OuterPageSize valor de nuevo a 10. En la página 3 (filas 21-25) el cálculo devolverá correctamente 5, y en todas las páginas 4 y mayores, el resultado negativo del cálculo será reemplazado por 0 (aunque probablemente sería más rápido devolver una fila de datos vacía inmediatamente en ese punto). - Adam V

Oh, ya veo. Bueno, mantengo mi opinión de que usar MS SQL Server 2000 hoy no vale la pena. - Bill Karwin

Oracle:

select * from (select foo from bar order by foo) where ROWNUM = x

Respondido 19 ago 08, 19:08

where ROWNUM = x solo funcionará para x = 1 en Oracle DB. es decir where ROWNUM = 2 no devolverá ninguna fila. - aff

En Oracle 12c, puede utilizar OFFSET..FETCH..ROWS opción con ORDER BY

Por ejemplo, para obtener el tercer registro desde arriba:

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;

Respondido 05 Feb 18, 12:02

Aquí tienes una rápida solución a tu confusión.

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

Aquí puede obtener la última fila completando N = 0, la segunda última por N = 1, la cuarta última completando N = 3 y así sucesivamente.

Esta es una pregunta muy común durante la entrevista y es muy simple y muy simple.

Además, si desea Cantidad, ID o algún orden de clasificación numérico, puede optar por la función CAST en MySQL.

SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1

Aquí Al completar N = 4, podrá obtener el quinto último registro de la cantidad más alta de la tabla CART. Puede ajustar el nombre de su campo y tabla y encontrar una solución.

contestado el 17 de mayo de 12 a las 10:05

AÑADIR:

LIMIT n,1

Eso limitará los resultados a un resultado a partir del resultado n.

Respondido 19 ago 08, 18:08

Por ejemplo, si desea seleccionar cada décima fila en MSSQL, puede usar;

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
  FROM TableName
) AS foo
WHERE rownumber % 10 = 0

Simplemente tome el MOD y cambie el número 10 aquí cualquier número que desee.

Respondido el 30 de diciembre de 11 a las 08:12

Para SQL Server, una forma genérica de ir por número de fila es la siguiente:

SET ROWCOUNT @row --@row = the row number you wish to work on.

Por Ejemplo:

set rowcount 20   --sets row to 20th row

select meat, cheese from dbo.sandwich --select columns from table at 20th row

set rowcount 0   --sets rowcount back to all rows

Esto devolverá la información de la fila 20. Asegúrese de poner el recuento de filas 0 después.

Respondido 07 Abr '19, 13:04

LIMIT n, 1 no funciona en MS SQL Server. Creo que es la única base de datos importante que no admite esa sintaxis. Para ser justos, no forma parte del estándar SQL, aunque tiene un soporte tan amplio que debería serlo. En todo excepto en el servidor SQL LIMIT funciona muy bien. Para el servidor SQL, no he podido encontrar una solución elegante.

Respondido 19 ago 08, 18:08

Excepto Oracle, DB2, bueno, casi todas las bases de datos de nivel empresarial en todo el mundo. PostgreSQL es la única base de datos con capacidad empresarial que admite la palabra clave LIMIT, y eso se debe principalmente a que, al ser de código abierto, debe ser accesible para la multitud de MySQL que ignora ACID. - David

@AlexD Esta "respuesta" se publicó en los viejos tiempos de Stackoverflow antes de que se implementaran los comentarios. Hubiera publicado esto como un comentario en otra respuesta, pero en ese momento, los comentarios no existían. - kibbee

Aquí hay una versión genérica de un sproc que escribí recientemente para Oracle que permite la paginación / clasificación dinámica: HTH

-- p_LowerBound = first row # in the returned set; if second page of 10 rows,
--                this would be 11 (-1 for unbounded/not set)
-- p_UpperBound = last row # in the returned set; if second page of 10 rows,
--                this would be 20 (-1 for unbounded/not set)

OPEN o_Cursor FOR
SELECT * FROM (
SELECT
    Column1,
    Column2
    rownum AS rn
FROM
(
    SELECT
        tbl.Column1,
        tbl.column2
    FROM MyTable tbl
    WHERE
        tbl.Column1 = p_PKParam OR
        tbl.Column1 = -1
    ORDER BY
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC,
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC
))
WHERE
    (rn >= p_lowerBound OR p_lowerBound = -1) AND
    (rn <= p_upperBound OR p_upperBound = -1);

Respondido 19 ago 08, 18:08

Pero, en realidad, ¿no son todos estos trucos de salón para un buen diseño de bases de datos en primer lugar? Las pocas veces que necesité una funcionalidad como esta, fue para una simple consulta única para hacer un informe rápido. Para cualquier trabajo real, usar trucos como estos es invitar a problemas. Si es necesario seleccionar una fila en particular, simplemente tenga una columna con un valor secuencial y termine con ella.

Respondido 19 ago 08, 20:08

Para el servidor SQL, lo siguiente devolverá la primera fila de la tabla proporcionada.

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

Puede recorrer los valores con algo como esto:

WHILE @constVar > 0
BEGIN
    declare @rowNumber int = @consVar;
       select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
       select TOP(@rowNumber - 1) * from [dbo].[someTable];  

       SET @constVar = @constVar - 1;    
END;

Respondido el 21 de junio de 18 a las 16:06

En Sybase SQL Anywhere:

SELECT TOP 1 START AT n * from table ORDER BY whatever

No olvides ORDER BY o no tiene sentido.

Respondido 19 ago 08, 20:08

T-SQL: selección de número de registro N de una tabla

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber

Where  RecordNumber --> Record Number to Select
       TableName --> To be Replaced with your Table Name

Por ejemplo, para seleccionar el quinto registro de una tabla Empleado, su consulta debe ser

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5

Respondido 26 Oct 11, 13:10

SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);

respondido 20 mar '12, 15:03

Nada lujoso, sin funciones especiales, en caso de que uses Caché como yo ...

SELECT TOP 1 * FROM (
  SELECT TOP n * FROM <table>
  ORDER BY ID Desc
)
ORDER BY ID ASC

Dado que tiene una columna de ID o una columna de marca de fecha en la que puede confiar.

Respondido 01 Oct 15, 14:10

SELECT
    top 1 *
FROM
    table_name
WHERE
    column_name IN (
        SELECT
            top N column_name
        FROM
            TABLE
        ORDER BY
            column_name
    )
ORDER BY
    column_name DESC

Escribí esta consulta para encontrar la enésima fila. Ejemplo con esta consulta sería

SELECT
    top 1 *
FROM
    Employee
WHERE
    emp_id IN (
        SELECT
            top 7 emp_id
        FROM
            Employee
        ORDER BY
            emp_id
    )
ORDER BY
    emp_id DESC

Respondido el 14 de diciembre de 16 a las 09:12

Llego un poco tarde a la fiesta aquí, pero lo he hecho sin necesidad de abrir ventanas o usar

WHERE x IN (...)
SELECT TOP 1
--select the value needed from t1
[col2]
FROM
(
   SELECT TOP 2 --the Nth row, alter this to taste
   UE2.[col1],
   UE2.[col2],
   UE2.[date],
   UE2.[time],
   UE2.[UID]
   FROM
   [table1] AS UE2
   WHERE
   UE2.[col1] = ID --this is a subquery 
   AND
   UE2.[col2] IS NOT NULL
   ORDER BY
   UE2.[date] DESC, UE2.[time] DESC --sorting by date and time newest first
) AS t1
ORDER BY t1.[date] ASC, t1.[time] ASC --this reverses the order of the sort in t1

Parece funcionar bastante rápido, aunque para ser justos, solo tengo alrededor de 500 filas de datos

Esto funciona en MSSQL

Respondido el 07 de diciembre de 20 a las 12:12

increíble que puedas encontrar un motor SQL ejecutando este ...

WITH sentence AS
(SELECT 
    stuff,
    row = ROW_NUMBER() OVER (ORDER BY Id)
FROM 
    SentenceType
    )
SELECT
    sen.stuff
FROM sentence sen
WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1

respondido 20 mar '12, 15:03

Así es como lo haría dentro de DB2 SQL, creo que el O / S almacena el RRN (número de registro relativo) dentro de la tabla;

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber

respondido 18 nov., 16:15

select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

Primero seleccione las 100 filas superiores ordenando en forma ascendente y luego seleccione la última fila ordenando en forma descendente y limite a 1. Sin embargo, esta es una declaración muy costosa ya que accede a los datos dos veces.

Respondido el 02 de junio de 17 a las 21:06

Me parece que, para ser eficiente, necesita 1) generar un número aleatorio entre 0 y uno menos que el número de registros de la base de datos, y 2) poder seleccionar la fila en esa posición. Desafortunadamente, las diferentes bases de datos tienen diferentes generadores de números aleatorios y diferentes formas de seleccionar una fila en una posición en un conjunto de resultados; por lo general, especifica cuántas filas omitir y cuántas filas desea, pero se hace de manera diferente para diferentes bases de datos. Aquí hay algo que me funciona en SQLite:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Depende de poder usar una subconsulta en la cláusula limit (que en SQLite es LIMIT , ) Seleccionar el número de registros en una tabla debería ser particularmente eficiente, ya que es parte de los metadatos de la base de datos, pero eso depende de la implementación de la base de datos. Además, no sé si la consulta realmente generará el conjunto de resultados antes de recuperar el registro N, pero espero que no sea necesario. Tenga en cuenta que no estoy especificando una cláusula de "orden por". Podría ser mejor "ordenar por" algo como la clave principal, que tendrá un índice. Obtener el registro N de un índice podría ser más rápido si la base de datos no puede obtener el registro N de la base de datos sin generar el conjunto de resultados. .

Respondido 17 Jul 17, 08:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.