web-dev-qa-db-fra.com

Renvoie des lignes entre une plage spécifique, avec une instruction select

Je cherche une expression comme celle-ci (avec SQL Server 2008)

SELECT TOP 10 columName FROM tableName

Mais au lieu de cela, j'ai besoin des valeurs comprises entre 10 et 20. Et je me demande s'il est possible de le faire en utilisant une seule instruction SELECT.

Par exemple, cela ne sert à rien:

SELECT columName FROM
(SELECT ROW_NUMBER() OVER(ORDER BY someId) AS RowNum, * FROM tableName) AS alias
WHERE RowNum BETWEEN 10 AND 20

Parce que la sélection entre crochets renvoie déjà tous les résultats, et je cherche à l'éviter pour des raisons de performance.

13
user1823901

Il y a une astuce avec row_number qui n'implique pas de trier toutes les lignes.

Essaye ça:

SELECT columName
FROM (SELECT ROW_NUMBER() OVER(ORDER BY (select NULL as noorder)) AS RowNum, *
      FROM tableName
     ) as alias
WHERE RowNum BETWEEN 10 AND 20

Vous ne pouvez pas utiliser une constante dans le order by. Toutefois, vous pouvez utiliser une expression qui renvoie une constante. SQL Server le reconnaît et renvoie simplement les lignes telles qu’elles ont été rencontrées, correctement énumérées.

8
Gordon Linoff

Pourquoi pensez-vous que SQL Server évaluerait l'intégralité de la requête interne? En supposant que votre colonne de tri soit indexée, il ne vous reste plus qu'à lire les 20 premières valeurs. Si vous êtes vraiment nerveux, vous pouvez le faire:

Select
  Id 
From (
  Select Top 20 -- note top 20
    Row_Number() Over(Order By Id) As RowNum,
    Id 
  From
    dbo.Test
  Order By
    Id
  ) As alias
Where
  RowNum Between 10 And 20
Order By
  Id

mais je suis presque sûr que le plan de requête est le même dans les deux cas.

(Vraiment) Corrigé selon le commentaire d'Aaron.

http://sqlfiddle.com/#!3/db162/6

3
Laurence

Utilisez SQL Server 2012 pour récupérer/ignorer! 

SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty, UnitPrice, LineTotal
FROM AdventureWorks2012.Sales.SalesOrderDetail
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

Rien de mieux que ce que vous décrivez pour les anciennes versions de SQL Server. Peut-être utiliser le CTE, mais il est peu probable que cela fasse une différence. 

WITH NumberedMyTable AS
(
    SELECT
        Id,
        Value,
        ROW_NUMBER() OVER (ORDER BY Id) AS RowNumber
    FROM
        MyTable
)
SELECT
    Id,
    Value
FROM
    NumberedMyTable
WHERE 
    RowNumber BETWEEN @From AND @To  

ou bien, vous pouvez supprimer les 10 premières lignes et obtenir les 10 suivantes, mais je double tout le monde.

1
RAS

Une autre option

SELECT TOP(11) columName
FROM dbo.tableName
ORDER BY
CASE WHEN ROW_NUMBER() OVER (ORDER BY someId) BETWEEN 10 AND 20 
     THEN ROW_NUMBER() OVER (ORDER BY someId) ELSE NULL END DESC
1

Vous pouvez créer une table temporaire ordonnée comme vous le souhaitez:

SELECT ROW_NUMBER () OVER (ORDER BY someId) AS RowNum, * FROM nomTable Dans ## tempTable ...

De cette façon, vous avez une liste ordonnée de lignes ..__ et vous pouvez simplement interroger les numéros suivants par numéro de ligne au lieu d'effectuer plusieurs fois l'interrogation interne.

0
user3688672