Domanda

Sono interessato ad apprendere alcuni modi (idealmente) indipendenti dal database per selezionare il file Nl'esima riga da una tabella di database.Sarebbe anche interessante vedere come ciò possa essere ottenuto utilizzando le funzionalità native dei seguenti database:

  • server SQL
  • MySQL
  • PostgreSQL
  • SQLite
  • Oracolo

Attualmente sto facendo qualcosa di simile in SQL Server 2005, ma sarei interessato a vedere gli approcci più agnostici di altri:

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

Credito per l'SQL sopra: Blog di Firoz Ansari

Aggiornamento: Vedere La risposta di Troels Arvin riguardo allo standard SQL. Troels, hai qualche link che possiamo citare?

È stato utile?

Soluzione

Esistono modi per farlo nelle parti opzionali dello standard, ma molti database supportano il proprio modo di farlo.

Davvero un buon sito che parla di questo e di altre cose http://troels.arvin.dk/db/rdbms/#select-limit.

Fondamentalmente, PostgreSQL e MySQL supportano il non standard:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 e MSSQL supportano le funzioni di finestra standard:

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

(che ho appena copiato dal sito linkato sopra poiché non utilizzo mai quei DB)

Aggiornamento: A partire da PostgreSQL 8.4 sono supportate le funzioni di finestra standard, quindi aspettatevi che il secondo esempio funzioni anche per PostgreSQL.

Aggiornamento: SQLite ha aggiunto il supporto per le funzioni finestra nella versione 3.25.0 il 15-09-2018, quindi entrambi i moduli funzionano anche in SQLite.

Altri suggerimenti

IL LIMIT / OFFSET sintassi in PostgreSQL È:

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

In questo esempio viene selezionata la ventunesima riga. OFFSET 20 sta dicendo a Postgres di saltare i primi 20 record.Se non specifichi un ORDER BY clausola, non esiste alcuna garanzia su quale record riceverai, il che è raramente utile.

Apparentemente lo standard SQL tace sul problema dei limiti al di fuori delle folli funzioni di windowing, motivo per cui ognuno lo implementa in modo diverso.

Non sono sicuro del resto, ma so che SQLite e MySQL non hanno alcun ordinamento delle righe "predefinito".In questi due dialetti, almeno, il seguente frammento prende la quindicesima voce da the_table, ordinandola in base alla data/ora in cui è stata aggiunta:

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

(ovviamente, dovresti aggiungere un campo DATETIME e impostarlo sulla data/ora in cui è stata aggiunta la voce...)

SQL 2005 e versioni successive hanno questa funzionalità integrata.Utilizza la funzione ROW_NUMBER().È eccellente per le pagine Web con una navigazione in stile << Prec. e Successivo >>:

Sintassi:

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

Sospetto che questo sia estremamente inefficiente, ma è un approccio abbastanza semplice, che ha funzionato su un piccolo set di dati su cui l'ho provato.

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

Ciò otterrebbe il quinto elemento, cambierebbe il secondo numero in alto per ottenere un ennesimo elemento diverso

Solo SQL server (credo) ma dovrebbe funzionare su versioni precedenti che non supportano ROW_NUMBER().

Verificalo su SQL Server:

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

Questo ti darà la decima RIGA della tabella emp!

1 piccola modifica:n-1 invece di n.

select *
from thetable
limit n-1, 1

Contrariamente a quanto sostengono alcune risposte, lo standard SQL non tace su questo argomento.

A partire da SQL:2003, è possibile utilizzare "funzioni finestra" per saltare righe e limitare i set di risultati.

E in SQL:2008 è stato aggiunto un approccio leggermente più semplice, utilizzando
OFFSET saltare ROWS FETCH FIRST N ROWS ONLY

Personalmente, non penso che l'aggiunta di SQL:2008 fosse realmente necessaria, quindi se fossi stato ISO, l'avrei tenuto fuori da uno standard già piuttosto ampio.

Oracolo:

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

Quando lavoravamo in MSSQL 2000, facevamo quello che chiamavamo il "triplo capovolgimento":

MODIFICATO

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

Non era elegante e non era veloce, ma funzionò.

SERVER SQL


Seleziona l'ennesimo record dall'alto

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

seleziona l'n'esimo record dal basso

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

Ecco una soluzione rapida alla tua confusione.

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

Qui puoi ottenere l'ultima riga riempiendo N=0, la penultima per N=1, la quartultima riempiendo N=3 e così via.

Questa è una domanda molto comune durante l'intervista ed è molto semplice.

Inoltre, se desideri un importo, un ID o un ordine di ordinamento numerico, puoi utilizzare la funzione CAST in MySQL.

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

Qui compilando N = 4 sarai in grado di ottenere il quintultimo record dell'importo più alto dalla tabella CART.Puoi adattare il nome del campo e della tabella e trovare una soluzione.

AGGIUNGERE:

LIMIT n,1

Ciò limiterà i risultati a un risultato a partire dal risultato n.

Ad esempio, se desideri selezionare ogni decima riga in MSSQL, puoi utilizzare;

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

Basta prendere il MOD e cambiare qui il numero 10 con qualsiasi numero tu voglia.

LIMIT n,1 non funziona in MS SQL Server.Penso che sia quasi l'unico database importante che non supporta quella sintassi.Per essere onesti, non fa parte dello standard SQL, sebbene sia così ampiamente supportato che dovrebbe esserlo.In tutto tranne SQL Server LIMIT funziona alla grande.Per il server SQL, non sono riuscito a trovare una soluzione elegante.

Ecco una versione generica di uno sproc che ho scritto di recente per Oracle che consente il paging/ordinamento dinamico - 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);

Ma in realtà, tutto questo non è in realtà solo qualche trucco da salotto per una buona progettazione di database?Le poche volte in cui ho avuto bisogno di funzionalità come questa è stato per una semplice query una tantum per creare un rapido rapporto.Per qualsiasi lavoro vero, usare trucchi come questi significa creare problemi.Se è necessaria la selezione di una riga particolare, è sufficiente avere una colonna con un valore sequenziale e terminarla.

In Oracle 12c, puoi utilizzare OFFSET..FETCH..ROWS opzione con ORDER BY

Ad esempio, per ottenere il terzo record dall'alto:

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

In Sybase SQL ovunque:

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

Non dimenticare l'ORDINE PER altrimenti non ha senso.

T-SQL: selezione dell'ennesimo numero di record da una tabella

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

Per es.per selezionare il quinto record da una tabella Employee, la tua query dovrebbe essere

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

Ho scritto questa query per trovare l'ennesima riga.Un esempio con questa query sarebbe

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

Per SQL Server, un modo generico per procedere in base al numero di riga è il seguente:

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

Per esempio:

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

Ciò restituirà le informazioni della ventesima riga.Assicurati di inserire il conteggio delle righe 0 in seguito.

incredibile che tu possa trovare un motore SQL che esegue questo ...

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

Niente di speciale, nessuna funzione speciale, nel caso usi Caché come faccio io...

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

Dato che hai una colonna ID o una colonna datestamp di cui ti puoi fidare.

Questo è il modo in cui lo farei all'interno di DB2 SQL, credo che l'RRN (numero di record relativo) sia memorizzato nella tabella dal sistema operativo;

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;

Seleziona prima le prime 100 righe ordinandole in ordine crescente, quindi seleziona l'ultima riga ordinandole in ordine decrescente e limita a 1.Tuttavia questa è un'affermazione molto costosa poiché accede ai dati due volte.

Mi sembra che, per essere efficiente, sia necessario 1) generare un numero casuale compreso tra 0 e uno in meno rispetto al numero di record del database e 2) essere in grado di selezionare la riga in quella posizione.Sfortunatamente, database diversi hanno generatori di numeri casuali diversi e modi diversi per selezionare una riga in una posizione in un set di risultati: di solito si specifica quante righe saltare e quante righe si desidera, ma viene fatto diversamente per database diversi.Ecco qualcosa che funziona per me in SQLite:

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

Dipende dalla possibilità di utilizzare una sottoquery nella clausola limite (che in SQLite è LIMIT <recs to skip>,<recs to take>). La selezione del numero di record in una tabella dovrebbe essere particolarmente efficiente, essendo parte del database metadati, ma ciò dipende dall'implementazione del database.Inoltre, non so se la query creerà effettivamente il set di risultati prima di recuperare l'ennesimo record, ma spero che non sia necessario.Tieni presente che non sto specificando una clausola "ordina per".Potrebbe essere meglio "ordinare per" qualcosa come la chiave primaria, che avrà un indice: ottenere l'ennesimo record da un indice potrebbe essere più veloce se il database non riesce a ottenere l'ennesimo record dal database stesso senza creare il set di risultati .

Per SQL Server, quanto segue restituirà la prima riga dalla tabella fornita.

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

Puoi scorrere i valori con qualcosa del genere:

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top