Existe-t-il un moyen dans SQL Server d’obtenir les résultats à partir d’un décalage donné? Par exemple, dans un autre type de base de données SQL, il est possible de faire:
SELECT * FROM MyTable OFFSET 50 LIMIT 25
pour obtenir des résultats 51-75. Cette construction ne semble pas exister dans SQL Server.
Comment puis-je accomplir cela sans charger toutes les lignes qui ne me dérangent pas? Merci!
Je voudrais éviter d'utiliser SELECT *
. Spécifiez les colonnes que vous souhaitez réellement, même s'il peut s'agir de toutes.
SQL Server 2005+
SELECT col1, col2
FROM (
SELECT col1, col2, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
FROM MyTable
) AS MyDerivedTable
WHERE MyDerivedTable.RowNum BETWEEN @startRow AND @endRow
SQL Server 2000
Effectuer une pagination efficace dans des jeux de résultats volumineux dans SQL Server 2000
Une méthode plus efficace pour la pagination dans des ensembles de résultats volumineux
Si vous souhaitez traiter toutes les pages dans l’ordre, il vous suffit de mémoriser la dernière valeur de clé de la page précédente et d’utiliser TOP (25) ... WHERE Key > @last_key ORDER BY Key
peut être la méthode la plus performante s’il existe des index appropriés pour permettre une recherche efficace, ou un curseur API . s'ils ne le font pas.
Pour la sélection d'une page arbitraire, la meilleure solution pour SQL Server 2005-2008 est probablement ROW_NUMBER
et BETWEEN
.
Pour SQL Server 2012+, vous pouvez utiliser la clause améliorée ORDER BY pour ce besoin.
SELECT *
FROM MyTable
ORDER BY OrderingColumn ASC
OFFSET 50 ROWS
FETCH NEXT 25 ROWS ONLY
Bien que il reste à voir à quel point cette option sera performante .
C'est à sens unique (SQL2000)
SELECT * FROM
(
SELECT TOP (@pageSize) * FROM
(
SELECT TOP (@pageNumber * @pageSize) *
FROM tableName
ORDER BY columnName ASC
) AS t1
ORDER BY columnName DESC
) AS t2
ORDER BY columnName ASC
et c'est une autre manière (SQL 2005)
;WITH results AS (
SELECT
rowNo = ROW_NUMBER() OVER( ORDER BY columnName ASC )
, *
FROM tableName
)
SELECT *
FROM results
WHERE rowNo between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize
Vous pouvez utiliser la fonction ROW_NUMBER()
pour obtenir ce que vous voulez:
SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t
WHERE RowNr BETWEEN 10 AND 20
Il y a OFFSET .. FETCH
dans SQL Server 2012, mais vous devrez spécifier une colonne ORDER BY
.
Si vous ne possédez aucune colonne explicite que vous pourriez transmettre sous la forme d'une colonne ORDER BY
(comme d'autres l'ont suggéré), vous pouvez utiliser cette astuce:
SELECT * FROM MyTable
ORDER BY @@VERSION
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY
... ou
SELECT * FROM MyTable
ORDER BY (SELECT 0)
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY
Nous l'utilisons dans jOOQ lorsque les utilisateurs ne spécifient pas explicitement un ordre. Cela produira alors un ordre assez aléatoire sans aucun coût supplémentaire.
Pour les tables avec davantage de colonnes de données, je préfère:
SELECT
tablename.col1,
tablename.col2,
tablename.col3,
...
FROM
(
(
SELECT
col1
FROM
(
SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum
FROM tablename
WHERE ([CONDITION])
)
AS T1 WHERE T1.RowNum BETWEEN [OFFSET] AND [OFFSET + LIMIT]
)
AS T2 INNER JOIN tablename ON T2.col1=tablename.col1
);
-
[CONDITION] can contain any WHERE clause for searching.
[OFFSET] specifies the start,
[LIMIT] the maximum results.
Les performances sur les tables contenant des données volumineuses telles que les BLOB sont bien meilleures, car la fonction ROW_NUMBER doit seulement parcourir une colonne, et seules les lignes correspondantes sont renvoyées avec toutes les colonnes.
Voir mon choix pour paginateur
SELECT TOP @limit * FROM (
SELECT ROW_NUMBER() OVER (ORDER BY colunx ASC) offset, * FROM (
-- YOU SELECT HERE
SELECT * FROM mytable
) myquery
) paginator
WHERE offset > @offset
Cela résout la pagination;)
SELECT TOP 75 * FROM MyTable
EXCEPT
SELECT TOP 50 * FROM MyTable
Ce qui suit affichera 25 enregistrements, à l'exception des 50 premiers enregistrements, fonctionne dans SQL Server 2012.
SELECT * FROM MyTable ORDER BY ID OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY;
vous pouvez remplacer l'ID en tant que votre exigence
En fonction de votre version, vous ne pouvez pas le faire directement, mais vous pouvez faire quelque chose de hacky comme
select top 25 *
from (
select top 75 *
from table
order by field asc
) a
order by field desc
où 'champ' est la clé.
Soyez prudent lorsque vous utilisez l'instruction row_number () OVER (ORDER BY), car performane est assez médiocre. Il en va de même pour l'utilisation d'expressions de table communes avec row_number (), ce qui est encore pire. J'utilise l'extrait suivant qui s'est révélé légèrement plus rapide que l'utilisation d'une variable de table avec une identité pour fournir le numéro de page.
DECLARE @Offset INT = 120000
DECLARE @Limit INT = 10
DECLARE @ROWCOUNT INT = @Offset+@Limit
SET ROWCOUNT @ROWCOUNT
SELECT * FROM MyTable INTO #ResultSet
WHERE MyTable.Type = 1
SELECT * FROM
(
SELECT *, ROW_NUMBER() OVER(ORDER BY SortConst ASC) As RowNumber FROM
(
SELECT *, 1 As SortConst FROM #ResultSet
) AS ResultSet
) AS Page
WHERE RowNumber BETWEEN @Offset AND @ROWCOUNT
DROP TABLE #ResultSet
J'utilise cette technique pour la pagination. Je ne vais pas chercher toutes les lignes. Par exemple, si ma page doit afficher les 100 premières lignes, je ne récupère que la clause 100 with where. La sortie du SQL doit avoir une clé unique.
Le tableau contient les éléments suivants:
ID, KeyId, Rank
Le même rang sera attribué à plus d'un KeyId.
SQL est select top 2 * from Table1 where Rank >= @Rank and ID > @Id
Pour la première fois, je passe 0 pour les deux. La deuxième fois passe 1 et 14. La 3ème fois passe 2 et 6.
La valeur du 10ème enregistrement Rank & Id est transmise au suivant
11 21 1
14 22 1
7 11 1
6 19 2
12 31 2
13 18 2
Cela aura le moins de stress sur le système
Dans SqlServer2005, vous pouvez effectuer les opérations suivantes:
DECLARE @Limit INT
DECLARE @Offset INT
SET @Offset = 120000
SET @Limit = 10
SELECT
*
FROM
(
SELECT
row_number()
OVER
(ORDER BY column) AS rownum, column2, column3, .... columnX
FROM
table
) AS A
WHERE
A.rownum BETWEEN (@Offset) AND (@Offset + @Limit-1)
Je cherche cette réponse depuis un moment (pour les requêtes génériques) et j'ai découvert une autre façon de procéder sur SQL Server 2000+ en utilisant ROWCOUNT et les curseurs et sans TOP ni aucune table temporaire.
En utilisant le SET ROWCOUNT [OFFSET+LIMIT]
, vous pouvez limiter les résultats et avec les curseurs, aller directement à la ligne de votre choix, puis en boucle jusqu'à la fin.
Donc, votre requête serait comme ceci:
SET ROWCOUNT 75 -- (50 + 25)
DECLARE MyCursor SCROLL CURSOR FOR SELECT * FROM pessoas
OPEN MyCursor
FETCH ABSOLUTE 50 FROM MyCursor -- OFFSET
WHILE @@FETCH_STATUS = 0 BEGIN
FETCH next FROM MyCursor
END
CLOSE MyCursor
DEALLOCATE MyCursor
SET ROWCOUNT 0
La meilleure façon de le faire sans perdre de temps à commander des enregistrements est la suivante:
select 0 as tmp,Column1 from Table1 Order by tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY
cela prend moins d'une seconde!
meilleure solution pour les grandes tables.
Le moyen le plus simple serait
SELECT * FROM table ORDER BY OrderColumn ASC LIMIT 50,25;
Cela fonctionne dans MySQL et (je pense) dans d'autres bases de données SQL.