web-dev-qa-db-fra.com

Décalage de ligne dans SQL Server

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! 

124
Alex

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

150
Brian Kim

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 .

94
Martin Smith

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
22
leoinfo

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
10
Matthias Meid

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.

6
Lukas Eder

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.

6
Arthur van Dijk

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;)

5
PerfectLion
SELECT TOP 75 * FROM MyTable
EXCEPT 
SELECT TOP 50 * FROM MyTable
3
Jithin Shaji

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

2
Shb

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é. 

2
Unsliced

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
2
Patrik Melander

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

1
Ravi Ramaswamy

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) 
1
Aheho

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
0
Capilé

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.

0
Pishgaman.org

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.

0
DataDeer.net