Come implementare LIMIT con SQL Server?


Risposte:


127

A partire da SQL SERVER 2005, è possibile farlo ...

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 10 AND 20;

o qualcosa del genere per le versioni 2000 e precedenti ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC

6
La seconda query ha esito negativo se nella tabella sono presenti ad esempio 14 righe. Ti dà le righe da 5 a 14, ma vuoi le righe da 11 a 14. In generale, non riesce per l'ultima "pagina" di un risultato, a meno che le righe totali non siano un multiplo di quella "pagina".
Bill Karwin,

147
Una cosa così semplice deve essere resa ancora più difficile dagli Stati membri!
Martin,

Ecco cosa ha funzionato per me in SQL Server Management Studio 2017: SELEZIONA * DA [dbo]. <Inserisci tabellaNome qui> DOVE @@ ROWCOUNT TRA <inserisci min qui> e <inserisci max qui> e <inserisci max qui>
Artorias2718

Semplicemente fantastico, funziona come un incantesimo
nell'istruzione

58

Clunky, ma funzionerà.

SELECT TOP 10 * FROM table WHERE id NOT IN (SELECT TOP 10 id FROM table ORDER BY id) FROM table ORDER BY id

L'omissione di MSSQL di una clausola LIMIT è criminale, IMO. Non dovresti fare questo tipo di soluzione alternativa.


Hai un altro suggerimento per aggirare questo?
Bigballs

L'ultima volta che ho avuto a che fare con MSSQL ho fatto molte ricerche su Google e questa è stata la migliore soluzione che ho trovato. Non è piacevole, ma funziona.
ceejayoz,

Questa soluzione funziona solo se il set di risultati include una colonna unica. Non è una soluzione generale per imitare LIMIT per qualsiasi query.
Bill Karwin,

1
Sono in un dilemma simile in questo momento ... Tuttavia, nel mio caso sono esasperato ... È ancora più criminale quando i cosiddetti dba "esperti" decidono che una chiave unica non è necessaria in una tabella ... QUALSIASI tabella ... Non sollevare nemmeno il tema delle chiavi esterne e dei vincoli!
Andrew Rollings,

Il problema con questo è che non gestisce molto bene le clausole WHERE ... Proverò le tabelle temporanee, poiché non funziona per me.
brutto pastello

37

A partire da SQL SERVER 2012, è possibile utilizzare la clausola FETCH OFFSET:

USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader 
ORDER BY SalesOrderID
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;
GO

http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx

Questo potrebbe non funzionare correttamente quando l'ordine non è univoco.

Se la query viene modificata in ORDER BY OrderDate, il set di risultati restituito non è come previsto.


L'utilizzo di "with" richiede solo metà del tempo per terminare l'interrogazione. Consulta la risposta di @Leon Tayson. Non ho idea di cosa abbia fatto Microsoft per renderlo così lento.
isHuman,

1
Perché questa non è la risposta accettata? Siamo nel 2018 per gridare forte!
Skipper

1
@Skipper giusto. quello accettato funziona ancora. Votiamo solo questo per riflettere l'aggiornamento.
kronn,

18

Questo è quasi un duplicato di una domanda che ho posto in ottobre: emulare la clausola LIMIT di MySQL in Microsoft SQL Server 2000

Se si utilizza Microsoft SQL Server 2000, non esiste una buona soluzione. Molte persone devono ricorrere all'acquisizione del risultato della query in una tabella temporanea con una IDENTITYchiave primaria. Quindi eseguire una query sulla colonna chiave primaria utilizzando una BETWEENcondizione.

Se si utilizza Microsoft SQL Server 2005 o versione successiva, si dispone di una ROW_NUMBER()funzione, quindi è possibile ottenere lo stesso risultato ma evitare la tabella temporanea.

SELECT t1.*
FROM (
    SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
    FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN @offset+1 AND @offset+@count;

Puoi anche scrivere questo come un'espressione di tabella comune come mostrato nella risposta di @Leon Tayson .


ROW_NUMBER () OVER (ORDER BY) ottiene punti per essere valido in ANSI SQL: 2003, sebbene il supporto in DBMS diversi da SQL Server sia molto discutibile. Ed è piuttosto goffo ovviamente ...
bobince

@bobince: risulta che Oracle, Microsoft SQL Server 2005, IBM DB2 e PostgreSQL 8.4 supportano tutte le funzioni della finestra. Ciò copre una grande maggioranza del mercato SQL. Il supporto è discutibile solo se si utilizza MySQL, SQLite o una versione precedente del DB sopra.
Bill Karwin,

16

Ecco come limito i risultati in MS SQL Server 2012:

SELECT * 
FROM table1
ORDER BY columnName
  OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

NOTA: OFFSETpuò essere utilizzato solo con o in tandem ORDER BY.

Per spiegare la riga di codice OFFSET xx ROWS FETCH NEXT yy ROW ONLY

Il xxè il numero record / riga che si desidera iniziare a tirare da nella tabella, vale a dire: se ci sono 40 record nella tabella 1, il codice di cui sopra si avvia tirando dalla riga 10.

Il yyè il numero di record / righe si vuole tirare dalla tabella.

Per basarsi sull'esempio precedente: se la tabella 1 ha 40 record e hai iniziato a tirare dalla riga 10 e prendi il prossimo set di 10 ( yy). Ciò significherebbe che il codice sopra estrarrà i record dalla tabella 1 a partire dalla riga 10 e terminando a 20. Tirando così le righe 10-20.

Controlla il link per maggiori informazioni su OFFSET


12
SELECT  *
FROM    (
        SELECT  TOP 20
                t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
        FROM    table1 t
        ORDER BY
                field1
        ) t
WHERE   rn > 10

Bene, ho appena verificato, SQL Server si è rivelato abbastanza intelligente da interrompere le condizioni ROW_NUMBER (), se è presente una colonna indicizzata nella clausola ORDER BY.
Quassnoi,

9

Sintatticamente, la query LIMIT MySQL è qualcosa del genere:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

Questo può essere tradotto in Microsoft SQL Server come

SELECT * FROM 
(
    SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table
) a
WHERE rnum > OFFSET

Ora la tua query select * from table1 LIMIT 10,20sarà così:

SELECT * FROM 
(
    SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table1
) a
WHERE rnum > 10 

2

Questo è uno dei motivi per cui cerco di evitare di usare MS Server ... ma comunque. A volte semplicemente non hai un'opzione (yei! E devo usare una versione obsoleta !!).

Il mio consiglio è di creare una tabella virtuale:

A partire dal:

SELECT * FROM table

Per:

CREATE VIEW v_table AS    
    SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table

Quindi esegui una query:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

Se i campi vengono aggiunti o rimossi, "riga" viene aggiornata automaticamente.

Il problema principale con questa opzione è che ORDER BY è stato risolto. Quindi, se si desidera un ordine diverso, è necessario creare un'altra vista.

AGGIORNARE

C'è un altro problema con questo approccio: se provi a filtrare i tuoi dati, non funzioneranno come previsto. Ad esempio, se lo fai:

SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20

DOVE si limita a quei dati che si trovano nelle righe tra 10 e 20 (invece di cercare l'intero set di dati e limitare l'output).


1

Questo è un approccio in più passaggi che funzionerà in SQL2000.

-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)

INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria

Select * FROM #foo where rowID > 10

1
SELECT 
    * 
FROM 
    (
        SELECT 
            top 20              -- ($a) number of records to show
            * 
        FROM
            (
                SELECT 
                    top 29      -- ($b) last record position
                    * 
                FROM 
                    table       -- replace this for table name (i.e. "Customer")
                ORDER BY 
                    2 ASC
            ) AS tbl1 
        ORDER BY 
            2 DESC
    ) AS tbl2 
ORDER BY 
    2 ASC;

-- Examples:

-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;

-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;

-- To calculate $b:
-- $b = ($a + position) - 1

-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;

È stata un'ottima soluzione per me.
Tyde,

1

Bisogna provare. Nella query di seguito, puoi visualizzare raggruppa, ordina per, Salta righe e limita righe.

select emp_no , sum(salary_amount) from emp_salary
Group by emp_no 
ORDER BY emp_no 
OFFSET 5 ROWS       -- Skip first 5 
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows


0

In SQL non esiste una parola chiave LIMIT. Se hai solo bisogno di un numero limitato di righe, dovresti usare una parola chiave TOP che è simile a un LIMIT.


0

Se il tuo ID è un tipo di identificatore univoco o il tuo ID nella tabella non è ordinato, devi procedere come segue.

select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5



Il codice sarà

selezionare * dal limite 2,5

0

meglio usarlo in MSSQLExpress 2017.

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;

--Dare una colonna [conteggio] e assegnare a ogni riga un conteggio univoco senza ordinare qualcosa, quindi selezionare nuovamente dove è possibile fornire i propri limiti .. :)


0

Uno dei modi possibili per ottenere risultati come di seguito, spero che questo possa essere d'aiuto.

declare @start int
declare @end int
SET @start = '5000';  -- 0 , 5000 ,
SET @end = '10000'; -- 5001, 10001
SELECT * FROM ( 
  SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
 ) a WHERE a.row > @start and a.row <= @end

0

Modo semplice

MYSQL:

SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'

MSSQL:

SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset' 
ROWS FETCH NEXT 'per_page' ROWS ONLY

ORDER BY è obbligatorio


-2

Se ricordo bene (è passato un po 'di tempo da quando mi sono dilettato con SQL Server) potresti essere in grado di usare qualcosa del genere: (dal 2005 in poi)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20

SQL Server 2012: Messaggio 207, livello 16, stato 1, riga 5 Nome colonna non valido 'RowNum'.
e-info128,

sembra che tu abbia un refuso nella tua dichiarazione da qualche parte. RowNum è il nome che assegniamo all'espressione. Pubblica il tuo problema con la fonte e la community ti aiuterà
Kris,

Questa non è sintassi valida. Non è possibile fare riferimento in WHEREun alias definito nella stessa SELECTclausola di livello .
ypercubeᵀᴹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.