Como seleccionar a n-ésima linha numa tabela de bases de dados SQL?

Estou interessado em aprender algumas (idealmente) maneiras agnósticas da base de dados de seleccionar a n th linha a partir de uma tabela de base de dados. Também seria interessante ver como isso pode ser alcançado usando a funcionalidade nativa das seguintes bases de dados:

  • servidor SQL
  • MySQL
  • PostgreSQL
  • SQLite
  • Oráculo
Estou a fazer algo como o seguinte no SQL Server 2005, mas estaria interessado em ver os outros mais agnósticos. abordagens:

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

Crédito pelo SQL acima: o Weblog da Firoz Ansari

actualização: ver a resposta de Troels Arvin sobre a norma SQL. Troels, tens alguma ligação que possamos citar?

Author: Community, 2008-08-19

29 answers

Existem maneiras de fazer isso em partes opcionais da norma, mas muitas bases de dados suportam sua própria maneira de fazê-lo.

Um site realmente bom que fala sobre isso e outras coisas é http://troels.arvin.dk/db/rdbms/#select-limit.

Basicamente, o PostgreSQL e o MySQL suportam o não-padrão:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 e MSSQL suportam as funções de janelas padrão:

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

(que acabei de copiar do site ligado acima, uma vez que nunca use esses DBs)

Update: As of PostgreSQL 8.4 the standard windowing functions are supported, so expect the second example to work for PostgreSQL as well.

 286
Author: Henrik Gustafsson, 2011-03-18 15:41:10

A LIMIT / OFFSET a sintaxe em PostgreSQL é:

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

Este exemplo selecciona a 21ª linha. Está a dizer ao Postgres para saltar os primeiros 20 discos. Se você não especificar uma cláusula ORDER BY, não há nenhuma garantia que registro você vai receber de volta, o que raramente é útil.

Aparentemente, a norma SQL é silenciosa sobre a questão limite fora das funções de janelas loucas, e é por isso que todos a implementam de forma diferente.
 81
Author: Neall, 2016-12-14 10:11:59

Não tenho a certeza sobre o resto, mas sei que o SQLite e o MySQL não têm nenhum pedido de linha "padrão". Nesses dois dialetos, pelo menos, o seguinte trecho agarra a décima quinta entrada da mesa, ordenando pela data / hora que foi adicionada:

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

(claro, você precisa ter um campo DATETIME adicionado, e configurá-lo para a data/hora que o item foi adicionado...)

 25
Author: Ellen Teapot, 2008-08-19 17:20:33

O SQL 2005 e superior tem esta funcionalidade incorporada. Use a função ROW_ numere (). É excelente para páginas web com uma navegação de estilo >:

Sintaxe:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23
 17
Author: Ben Breen, 2016-12-14 10:16:27
Suspeito que isto seja extremamente ineficiente, mas é uma abordagem muito simples, que funcionou num pequeno conjunto de dados que eu experimentei.
select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

Isto iria obter o quinto item, mudar o segundo número de topo para obter um item diferente

Só o servidor SQL (penso), mas deve trabalhar em versões mais antigas que não suportam o ROW_NUMBER().

 16
Author: Tim Saunders, 2008-08-19 17:34:38

1 pequena alteração: n-1 em vez de n.

select *
from thetable
limit n-1, 1
 11
Author: Nick Berardi, 2012-12-03 23:35:02

Verifique no servidor SQL:

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp
Isto vai dar-te a 10ª fila da mesa emp!
 11
Author: Rameshwar Pawale, 2015-04-09 20:25:14
Ao contrário do que algumas das respostas afirmam, a norma SQL não é silenciosa em relação a este assunto.

Desde SQL: 2003, você tem sido capaz de usar "funções de janela" para saltar linhas e limitar os conjuntos de resultados.

E em SQL:2008, foi acrescentada uma abordagem ligeiramente mais simples, utilizando
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

{[[2]}pessoalmente, não acho que a adição do SQL:2008 fosse realmente necessária, por isso, se eu fosse ISO, tê-la-ia mantido fora de um padrão já bastante grande.
 8
Author: Troels Arvin, 2017-09-20 19:21:48

Oráculo:

select * from (select foo from bar order by foo) where ROWNUM = x
 6
Author: Mark Harrison, 2008-08-19 18:51:29
Quando costumávamos trabalhar no MSSQL 2000, fizemos o que chamávamos de "Triple-flip":

Edição

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
Não era elegante e não era rápido, mas funcionou.
 6
Author: Adam V, 2011-12-30 15:31:24

SERVIDOR SQL


Seleccione o n ' ésimo registo do topo

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

Seleccione o n ' ésimo registo do fundo

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n
 6
Author: Aditya, 2014-02-19 04:35:17
Aqui está uma solução rápida da sua confusão.
SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

Aqui você pode obter a última linha preenchendo N=0, o segundo último por N=1, o quarto último preenchendo N = 3 e assim por diante.

Esta é uma questão muito comum na entrevista e é muito simples.

Além disso, se quiser quantidade, ID ou alguma ordem de ordenação numérica, O u poderá ir para a função CAST no MySQL.

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

Aqui preenchendo N = 4, poderá obter o quinto último registo da quantidade mais elevada da tabela CART. Você pode caber seu campo e nome da tabela e chegar a uma solução.

 3
Author: Amit Shah, 2012-05-17 09:29:27

Adicionar:

LIMIT n,1

Isso irá limitar os resultados a um resultado a partir do resultado n.

 2
Author: Andrew G. Johnson, 2008-08-19 17:14:05

O limite n, 1 não funciona no servidor de MS SQL. Acho que é a única base de dados importante que não suporta essa sintaxe. Para ser justo, não faz parte do padrão SQL, embora seja tão amplamente apoiado que deveria ser. Em tudo, exceto o limite de servidor SQL funciona muito bem. Para o servidor SQL, eu não fui capaz de encontrar uma solução elegante.

 2
Author: Kibbee, 2008-08-19 17:18:06

Aqui está uma versão genérica de um sproc que escrevi recentemente para a Oracle que permite uma chamada de pessoas/ordenação 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);
 2
Author: Greg Hurlman, 2008-08-19 17:19:01
Mas, na verdade, isto não são apenas truques de salão para um bom desenho de bases de dados? As poucas vezes que eu precisava de funcionalidade como esta era para uma simples consulta One off para fazer um relatório rápido. Para qualquer trabalho a sério, usar truques como estes é um convite para problemas. Se a seleção de uma linha em particular é necessária, então basta ter uma coluna com um valor sequencial e ser feito com ela.
 2
Author: , 2008-08-19 19:06:57

Por exemplo, se quiser seleccionar todas as 10 linhas em MSSQL, pode usar;

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
  FROM TableName
) AS foo
WHERE rownumber % 10 = 0
Pegue no MOD e mude o número 10 para o número que quiser.
 2
Author: E-A, 2011-12-30 08:41:20

In Sybase SQL Anywhere:

SELECT TOP 1 START AT n * from table ORDER BY whatever
Não te esqueças da ordem ou não faz sentido.
 1
Author: Graeme Perrow, 2008-08-19 19:06:59

Para O servidor SQL, uma forma genérica de ir pelo número da linha é como tal: Define o número do ROWCOUNT @row --@row = o número da linha em que deseja trabalhar.

Por Exemplo:

Mudar o número de linhas 20 --muda a linha para a 20ª linha

Seleccionar carne, queijo do dbo.sandwich -- select columns from table at 20th row

Definir o número de linhas 0 --configura o número de linhas de volta para todas as linhas

Isto vai devolver a informação da 20ª fila. Não se esqueça de colocar o número 0 depois. Conheço o noobish, mas sou. um SQL noob e eu usámo-lo, o que posso dizer?
 1
Author: , 2009-06-22 17:00:08

T-SQL-seleccionar o n'. º número de Registo de uma tabela

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

Para, por exemplo, seleccionar 5. o registo de um empregado de mesa, a sua consulta deve ser

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5
 1
Author: Sangeeth Krishna, 2011-10-26 12:46:41
SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);
 1
Author: 2 revs, 2 users 62%Rahul Sharma, 2012-03-20 15:48:43
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
Escrevi esta pergunta para encontrar a Nth row. Exemplo com esta consulta seria
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
 1
Author: Arjun Chiddarwar, 2016-12-14 09:52:07
Inacreditável que encontres um motor SQL a executar 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
 0
Author: jrEving, 2012-03-20 15:48:30
Nada de extravagante, nada de funções especiais, no caso de usares Caché como eu...
SELECT TOP 1 * FROM (
  SELECT TOP n * FROM <table>
  ORDER BY ID Desc
)
ORDER BY ID ASC

Dado que tem uma coluna de ID ou uma coluna de datestamp em que pode confiar.

 0
Author: Scott Beeson, 2015-10-01 13:16:54

É assim que eu o faria dentro do DB2 SQL, acredito que o RRN (número de registo relativo) é armazenado dentro da tabela pelo o / S;

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber
 0
Author: RDKells, 2016-11-18 15:12:02
select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

Primeiro seleccione as 100 linhas de topo ordenando em ascendente e depois seleccione a última linha ordenando em descendente e limite para 1. No entanto, esta é uma declaração muito cara, uma vez que ele acessar os dados duas vezes.

 0
Author: Dwipam Katariya, 2017-06-02 20:26:39
{[[2]} Parece-me que, para ser eficiente, você precisa de 1) gerar um número aleatório entre 0 e um a menos do que o número de registros de banco de dados, e 2) ser capaz de selecionar a linha nessa posição. Infelizmente, diferentes bases de dados têm diferentes geradores de números aleatórios e diferentes maneiras de selecionar uma linha em uma posição em um conjunto de resultados - geralmente você especifica quantas linhas para saltar e quantas linhas você deseja, mas é feito de forma diferente para diferentes bases de dados. Aqui está algo que funciona para eu em SQLite:
select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Ele depende de ser capaz de usar uma subquery na cláusula limite (que em SQLite é limite ,) selecionar o número de registros em uma tabela deve ser particularmente eficiente, sendo parte dos meta dados da base de dados, mas isso depende da implementação da base de dados. Além disso, eu não sei se a consulta irá realmente construir o conjunto de resultados antes de recuperar o registro Nth, mas eu espero que ele não precisa. Note que não estou a especificar um "ordem por" cláusula. Pode ser melhor "Ordenar" por algo como a chave primária, que terá um índice - obter o Registro n-ésimo de um índice pode ser mais rápido se o banco de dados não pode obter o Registro n-ésimo do próprio banco de dados sem construir o conjunto de resultados.

 0
Author: user1738579, 2017-07-17 07:46:08

No Oracle 12c, pode usar a opção OFFSET..FETCH..ROWS com ORDER BY

Por exemplo, para obter o 3º disco do topo:

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;
 0
Author: Kaushik Nayak, 2018-02-05 12:43:42

Para o servidor SQL, o seguinte irá devolver a primeira linha de dar a tabela.

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

Você pode percorrer os valores com algo como isto:

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;
 0
Author: sony vizio, 2018-06-21 15:45:35