Pergunta

Estou interessado em aprender algumas maneiras (idealmente) independentes de banco de dados de selecionar o na linha de uma tabela de banco de dados.Também seria interessante ver como isso pode ser conseguido usando a funcionalidade nativa dos seguintes bancos de dados:

  • servidor SQL
  • MySQL
  • PostgreSQL
  • SQLite
  • Oráculo

Atualmente estou fazendo algo parecido com o seguinte no SQL Server 2005, mas estaria interessado em ver outras abordagens mais agnósticas:

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: Blog de Firoz Ansari

Atualizar: Ver Resposta de Troels Arvin em relação ao padrão SQL. Troels, você tem algum link que possamos citar?

Foi útil?

Solução

Existem maneiras de fazer isso em partes opcionais do padrão, mas muitos bancos de dados suportam sua própria maneira de fazer isso.

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

Basicamente, PostgreSQL e 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 vinculado acima, pois nunca uso esses bancos de dados)

Atualizar: A partir do PostgreSQL 8.4, as funções de janelas padrão são suportadas, portanto, espere que o segundo exemplo funcione também para o PostgreSQL.

Atualizar: SQLite adicionou suporte a funções de janela na versão 3.25.0 em 15/09/2018 para que ambos os formulários também funcionem em SQLite.

Outras dicas

O LIMIT / OFFSET sintaxe no PostgreSQL é:

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

Este exemplo seleciona a 21ª linha. OFFSET 20 está dizendo ao Postgres para pular os primeiros 20 registros.Se você não especificar um ORDER BY cláusula, não há garantia de qual registro você receberá, o que raramente é útil.

Aparentemente, o padrão SQL é omisso sobre a questão do limite fora das funções malucas de janelas, e é por isso que todo mundo o implementa de maneira diferente.

Não tenho certeza sobre o resto, mas sei que SQLite e MySQL não têm nenhuma ordem de linha "padrão".Nesses dois dialetos, pelo menos, o trecho a seguir captura a 15ª entrada de the_table, classificando pela data/hora em que foi adicionada:

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

(é claro, você precisaria adicionar um campo DATETIME e configurá-lo para a data/hora em que a entrada foi adicionada...)

O SQL 2005 e superior possuem esse recurso integrado.Use a função ROW_NUMBER().É excelente para páginas da web com navegação no estilo << Anterior e Próximo >>:

Sintaxe:

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

Suspeito que isso seja extremamente ineficiente, mas é uma abordagem bastante simples, que funcionou em um pequeno conjunto de dados em que experimentei.

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

Isso obteria o 5º item, alteraria o segundo número superior para obter um enésimo item diferente

Somente servidor SQL (eu acho), mas deve funcionar em versões mais antigas que não suportam ROW_NUMBER().

Verifique no SQL Server:

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

Isso lhe dará a 10ª LINHA da tabela emp!

1 pequena mudança:n-1 em vez de n.

select *
from thetable
limit n-1, 1

Ao contrário do que afirmam algumas respostas, o padrão SQL não é omisso em relação a esse assunto.

Desde SQL:2003, você pode usar "funções de janela" para pular linhas e limitar conjuntos de resultados.

E no SQL:2008, uma abordagem um pouco mais simples foi adicionada, usando
OFFSET pular ROWS FETCH FIRST n ROWS ONLY

Pessoalmente, não acho que a adição do SQL:2008 fosse realmente necessária; portanto, se eu fosse ISO, o teria mantido fora de um padrão já bastante grande.

Oráculo:

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

Quando trabalhávamos no MSSQL 2000, fazíamos o que chamamos de "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

Não foi elegante e não foi rápido, mas funcionou.

SERVIDOR SQL


Selecione o nº registro do topo

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

selecione o nº registro da parte inferior

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

Aqui está uma solução rápida para sua confusão.

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

Aqui você pode obter a última linha preenchendo N = 0, a penúltima por N = 1, a quarta por preenchendo N = 3 e assim por diante.

Essa é uma pergunta muito comum durante a entrevista e é muito simples.

Além disso, se você quiser Quantidade, ID ou alguma ordem de classificação numérica, você pode usar 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, você poderá obter o quinto último registro do maior valor da tabela CART.Você pode ajustar o nome do campo e da tabela e encontrar uma solução.

ADICIONAR:

LIMIT n,1

Isso limitará os resultados a um resultado começando no resultado n.

Por exemplo, se quiser selecionar cada 10ª linha no MSSQL, você pode usar;

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

Basta pegar o MOD e alterar o número 10 aqui para qualquer número que desejar.

LIMIT n,1 não funciona no MS SQL Server.Acho que é o único grande banco de dados que não suporta essa sintaxe.Para ser justo, não faz parte do padrão SQL, embora seja tão amplamente suportado que deveria ser.Em tudo, exceto no SQL Server LIMIT, funciona muito bem.Para o SQL Server, não consegui encontrar uma solução elegante.

Aqui está uma versão genérica de um sproc que escrevi recentemente para Oracle que permite paginação/classificaçã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);

Mas, na verdade, tudo isso não é apenas truques de salão para um bom design de banco de dados?As poucas vezes em que precisei de uma funcionalidade como essa, foi para uma consulta simples e única para fazer um relatório rápido.Para qualquer trabalho real, usar truques como esses é um convite a problemas.Se for necessário selecionar uma linha específica, basta ter uma coluna com um valor sequencial e pronto.

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

Por exemplo, para obter o terceiro registro do início:

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

No Sybase SQL Anywhere:

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

Não se esqueça do ORDER BY ou não terá sentido.

T-SQL - Selecionando o enésimo RecordNumber 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

Por exemplopara selecionar o 5º registro de uma tabela Employee, sua consulta deve ser

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5
SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);
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

Eu escrevi esta consulta para encontrar a enésima linha.Um 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

Para o SQL Server, uma maneira genérica de usar o número da linha é:

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

Por exemplo:

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

Isso retornará as informações da 20ª linha.Certifique-se de colocar o rowcount 0 depois.

inacreditável que você possa encontrar um mecanismo SQL executando 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

Nada sofisticado, sem funções especiais, caso você use o Caché como eu...

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

Dado que você tem uma coluna de ID ou uma coluna de carimbo de data em que pode confiar.

É assim que eu faria no DB2 SQL, acredito que o RRN (número de registro relativo) é armazenado na tabela pelo O/S;

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber
select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

Primeiro selecione as 100 primeiras linhas ordenando em ordem crescente e, em seguida, selecione a última linha ordenando em ordem decrescente e limite a 1.No entanto, esta é uma declaração muito cara, pois acessa os dados duas vezes.

Parece-me que, para ser eficiente, você precisa 1) gerar um número aleatório entre 0 e um a menos que o número de registros do banco de dados e 2) ser capaz de selecionar a linha nessa posição.Infelizmente, diferentes bancos 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 deseja pular e quantas linhas deseja, mas isso é feito de maneira diferente para bancos de dados diferentes.Aqui está algo que funciona para mim no SQLite:

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

Depende de ser capaz de usar uma subconsulta na cláusula limit (que no SQLite é LIMIT <recs to skip>,<recs to take>) Selecionar o número de registros em uma tabela deve ser particularmente eficiente, fazendo parte do banco de dados metadados, mas isso depende da implementação do banco de dados.Além disso, não sei se a consulta realmente criará o conjunto de resultados antes de recuperar o enésimo registro, mas espero que não seja necessário.Observe que não estou especificando uma cláusula "order by".Talvez seja melhor "ordenar por" algo como a chave primária, que terá um índice - obter o enésimo registro de um índice pode ser mais rápido se o banco de dados não puder obter o enésimo registro do próprio banco de dados sem construir o conjunto de resultados .

Para o servidor SQL, o seguinte retornará a primeira linha da tabela fornecida.

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

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;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top