Quelle est la meilleure façon (en termes de performances) de paginer les résultats dans SQL Server 2000, 2005, 2008, 2012 si vous souhaitez également obtenir le nombre total de résultats (avant la pagination)?
Quelle est la meilleure façon (en termes de performances) de paginer les résultats dans SQL Server 2000, 2005, 2008, 2012 si vous souhaitez également obtenir le nombre total de résultats (avant la pagination)?
Réponses:
Obtenir le nombre total de résultats et paginer sont deux opérations différentes. Pour les besoins de cet exemple, supposons que la requête que vous traitez est
SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
Dans ce cas, vous détermineriez le nombre total de résultats en utilisant:
SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'
... qui peut sembler inefficace, mais est en fait assez performant, en supposant que tous les index, etc. sont correctement configurés.
Ensuite, pour obtenir les résultats réels de manière paginée, la requête suivante serait la plus efficace:
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, *
FROM Orders
WHERE OrderDate >= '1980-01-01'
) AS RowConstrainedResult
WHERE RowNum >= 1
AND RowNum < 20
ORDER BY RowNum
Cela renverra les lignes 1 à 19 de la requête d'origine. La chose intéressante ici, en particulier pour les applications Web, est que vous n'avez pas à conserver d'état, sauf les numéros de ligne à renvoyer.
Enfin, Microsoft SQL Server 2012 est sorti, j'aime beaucoup sa simplicité pour une pagination, vous n'avez pas besoin d'utiliser des requêtes complexes comme répondu ici.
Pour obtenir les 10 lignes suivantes, exécutez simplement cette requête:
SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
Points clés à considérer lors de son utilisation:
ORDER BY
est obligatoire d'utiliser la OFFSET ... FETCH
clause.OFFSET
clause est obligatoire avec FETCH
. Vous ne pouvez pas utiliserORDER BY ...
FETCH
.TOP
ne peut pas être combiné avec OFFSET
et FETCH
dans la même expression de requête.LISTAGG()
/ GROUP_CONCAT()
.
FOR XML
: stackoverflow.com/a/273330/429949
FOR XML PATH ('')
. Tout d'abord, il remplace les caractères de contrôle XML par des codes d'entité XML. Je espère que vous n'avez pas <
, >
ou &
dans vos données! Deuxièmement, la FOR XML PATH ('')
syntaxe en fait non utilisée est utilisée de cette manière. Vous êtes censé spécifier une colonne nommée ou un autre nom d'élément. Ne faire ni l'un ni l'autre n'est pas dans le document, ce qui signifie que le comportement n'est pas fiable. Troisièmement, plus nous acceptons la FOR XML PATH ('')
syntaxe cassée , moins il est probable que MS fournisse réellement une fonction réelle LISTAGG() [ OVER() ]
comme ils en avaient besoin.
Incroyablement, aucune autre réponse n'a mentionné le moyen le plus rapide de paginer dans toutes les versions de SQL Server. Les décalages peuvent être terriblement lents pour les grands nombres de pages, comme c'est le cas ici . Il existe un moyen entièrement différent et beaucoup plus rapide d'effectuer la pagination en SQL. Ceci est souvent appelé la "méthode de recherche" ou la "pagination par jeu de clés" comme décrit dans cet article de blog ici .
SELECT TOP 10 first_name, last_name, score, COUNT(*) OVER()
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
Les valeurs @previousScore
et @previousPlayerId
sont les valeurs respectives du dernier enregistrement de la page précédente. Cela vous permet de récupérer la page "suivante". Si la ORDER BY
direction est ASC
, utilisez simplement à la >
place.
Avec la méthode ci-dessus, vous ne pouvez pas passer immédiatement à la page 4 sans avoir d'abord récupéré les 40 enregistrements précédents. Mais souvent, vous ne voulez pas sauter aussi loin de toute façon. Au lieu de cela, vous obtenez une requête beaucoup plus rapide qui peut être en mesure de récupérer des données en temps constant, en fonction de votre indexation. De plus, vos pages restent "stables", peu importe si les données sous-jacentes changent (par exemple à la page 1, pendant que vous êtes à la page 4).
C'est le meilleur moyen d'implémenter la pagination lors du chargement paresseux de données supplémentaires dans des applications Web, par exemple.
Notez que la "méthode de recherche" est également appelée pagination du jeu de clés .
La COUNT(*) OVER()
fonction de fenêtre vous aidera à compter le nombre total d'enregistrements "avant la pagination". Si vous utilisez SQL Server 2000, vous devrez recourir à deux requêtes pour le COUNT(*)
.
OFFSET .. FETCH
ou avec des ROW_NUMBER()
astuces précédentes .
RowNumber
me donne 10 éléments cohérents par page. [3] cela ne fonctionne pas avec les grilles existantes qui supposent pagenumber
et pagesize
.
À partir de SQL Server 2012, nous pouvons utiliser OFFSET
et FETCH NEXT
Clause pour réaliser la pagination.
Essayez ceci, pour SQL Server:
Dans SQL Server 2012, une nouvelle fonctionnalité a été ajoutée dans la clause ORDER BY pour interroger l'optimisation d'un ensemble de données, ce qui facilite le travail avec la pagination des données pour quiconque écrit en T-SQL ainsi que pour l'ensemble du plan d'exécution dans SQL Server.
Sous le script T-SQL avec la même logique utilisée dans l'exemple précédent.
--CREATING A PAGING WITH OFFSET and FETCH clauses IN "SQL SERVER 2012" DECLARE @PageNumber AS INT, @RowspPage AS INT SET @PageNumber = 2 SET @RowspPage = 10 SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE FROM TB_EXAMPLE ORDER BY ID_EXAMPLE OFFSET ((@PageNumber - 1) * @RowspPage) ROWS FETCH NEXT @RowspPage ROWS ONLY;
MSDN: ROW_NUMBER (Transact-SQL)
Renvoie le numéro séquentiel d'une ligne dans une partition d'un jeu de résultats, en commençant à 1 pour la première ligne de chaque partition.
L'exemple suivant retourne des lignes avec les nombres 50 à 60 inclus dans l'ordre de OrderDate.
WITH OrderedOrders AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY FirstName DESC) AS RowNumber,
FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
FROM [dbo].[vSalesPerson]
)
SELECT RowNumber,
FirstName, LastName, Sales YTD
FROM OrderedOrders
WHERE RowNumber > 50 AND RowNumber < 60;
RowNumber FirstName LastName SalesYTD
--- ----------- ---------------------- -----------------
1 Linda Mitchell 4251368.54
2 Jae Pak 4116871.22
3 Michael Blythe 3763178.17
4 Jillian Carson 3189418.36
5 Ranjit Varkey Chudukatil 3121616.32
6 José Saraiva 2604540.71
7 Shu Ito 2458535.61
8 Tsvi Reiter 2315185.61
9 Rachel Valdez 1827066.71
10 Tete Mensa-Annan 1576562.19
11 David Campbell 1573012.93
12 Garrett Vargas 1453719.46
13 Lynn Tsoflias 1421810.92
14 Pamela Ansman-Wolfe 1352577.13
Il existe un bon aperçu des différentes techniques de pagination sur http://www.codeproject.com/KB/aspnet/PagingLarge.aspx
J'ai utilisé la méthode ROWCOUNT assez souvent, principalement avec SQL Server 2000 (fonctionnera également avec 2005 et 2008, il suffit de mesurer les performances par rapport à ROW_NUMBER), c'est rapide comme l'éclair, mais vous devez vous assurer que les colonnes triées ont (principalement ) des valeurs uniques.
Pour SQL Server 2000, vous pouvez simuler ROW_NUMBER () à l'aide d'une variable de table avec une colonne IDENTITY:
DECLARE @pageNo int -- 1 based
DECLARE @pageSize int
SET @pageNo = 51
SET @pageSize = 20
DECLARE @firstRecord int
DECLARE @lastRecord int
SET @firstRecord = (@pageNo - 1) * @pageSize + 1 -- 1001
SET @lastRecord = @firstRecord + @pageSize - 1 -- 1020
DECLARE @orderedKeys TABLE (
rownum int IDENTITY NOT NULL PRIMARY KEY CLUSTERED,
TableKey int NOT NULL
)
SET ROWCOUNT @lastRecord
INSERT INTO @orderedKeys (TableKey) SELECT ID FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
SET ROWCOUNT 0
SELECT t.*
FROM Orders t
INNER JOIN @orderedKeys o ON o.TableKey = t.ID
WHERE o.rownum >= @firstRecord
ORDER BY o.rownum
Cette approche peut être étendue aux tables avec des clés multi-colonnes, et elle n'entraîne pas la surcharge de performances de l'utilisation de OR (qui ignore l'utilisation de l'index). L'inconvénient est la quantité d'espace temporaire utilisée si l'ensemble de données est très volumineux et que l'on se trouve près de la dernière page. Je n'ai pas testé les performances du curseur dans ce cas, mais cela pourrait être mieux.
Notez que cette approche pourrait être optimisée pour la première page de données. En outre, ROWCOUNT a été utilisé car TOP n'accepte pas de variable dans SQL Server 2000.
La meilleure façon de paginer dans SQL Server 2012 est d'utiliser le décalage et la récupération suivante dans une procédure stockée. Mot - clé OFFSET - Si nous utilisons offset avec la clause order by, la requête ignorera le nombre d'enregistrements que nous avons spécifié dans OFFSET n Rows.
Mots - clés FETCH NEXT - Lorsque nous utilisons Fetch Next uniquement avec une clause order by, il renvoie le nombre de lignes que vous souhaitez afficher dans la pagination, sans décalage, puis SQL génère une erreur. voici l'exemple donné ci-dessous.
create procedure sp_paging
(
@pageno as int,
@records as int
)
as
begin
declare @offsetcount as int
set @offsetcount=(@pageno-1)*@records
select id,bs,variable from salary order by id offset @offsetcount rows fetch Next @records rows only
end
vous pouvez l'exécuter comme suit.
exec sp_paging 2,3
Ce sont mes solutions pour paginer le résultat d'une requête côté serveur SQL. ces approches sont différentes entre SQL Server 2008 et 2012. De plus, j'ai ajouté le concept de filtrage et de tri par une seule colonne. Il est très efficace lorsque vous effectuez une recherche, un filtrage et une commande dans votre Gridview.
Avant de tester, vous devez créer un exemple de table et insérer une ligne dans ce tableau: (Dans le monde réel, vous devez modifier la clause Where en tenant compte des champs de votre table et peut-être avez-vous une jointure et une sous-requête dans la partie principale de select)
Create Table VLT
(
ID int IDentity(1,1),
Name nvarchar(50),
Tel Varchar(20)
)
GO
Insert INTO VLT
VALUES
('NAME' + Convert(varchar(10),@@identity),'FAMIL' + Convert(varchar(10),@@identity))
GO 500000
Dans tous ces exemples, je souhaite interroger 200 lignes par page et je récupère la ligne pour le numéro de page 1200.
Dans SQL Server 2008, vous pouvez utiliser le concept CTE. Pour cette raison, j'ai écrit deux types de requêtes pour SQL Server 2008+
- SQL Server 2008+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
) AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
GO
Et deuxième solution avec CTE dans SQL Server 2008+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
- SQL Server 2012+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN Data.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN Data.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN Data.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN Data.Tel END ASC
OFFSET @PageSize * (@PageNumber - 1) ROWS FETCH NEXT @PageSize ROWS ONLY;
Dans le cas d'utilisation, les éléments suivants semblent faciles à utiliser et rapides. Définissez simplement le numéro de page.
use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6;
with result as(
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
)
select SalesOrderDetailID, SalesOrderID, ProductID from result
WHERE result.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
également sans CTE
use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6
SELECT SalesOrderDetailID, SalesOrderID, ProductID
FROM (
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
) AS SOD
WHERE SOD.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
Eh bien, j'ai utilisé l'exemple de requête suivant dans ma base de données SQL 2000, cela fonctionne bien pour SQL 2005 aussi. La puissance qu'il vous donne est dynamiquement ordonnée en utilisant plusieurs colonnes. Je vous le dis ... c'est puissant :)
ALTER PROCEDURE [dbo].[RE_ListingReports_SelectSummary]
@CompanyID int,
@pageNumber int,
@pageSize int,
@sort varchar(200)
AS
DECLARE @sql nvarchar(4000)
DECLARE @strPageSize nvarchar(20)
DECLARE @strSkippedRows nvarchar(20)
DECLARE @strFields nvarchar(4000)
DECLARE @strFilter nvarchar(4000)
DECLARE @sortBy nvarchar(4000)
DECLARE @strFrom nvarchar(4000)
DECLARE @strID nvarchar(100)
If(@pageNumber < 0)
SET @pageNumber = 1
SET @strPageSize = CAST(@pageSize AS varchar(20))
SET @strSkippedRows = CAST(((@pageNumber - 1) * @pageSize) AS varchar(20))-- For example if pageNumber is 5 pageSize is 10, then SkippedRows = 40.
SET @strID = 'ListingDbID'
SET @strFields = 'ListingDbID,
ListingID,
[ExtraRoom]
'
SET @strFrom = ' vwListingSummary '
SET @strFilter = ' WHERE
CompanyID = ' + CAST(@CompanyID As varchar(20))
End
SET @sortBy = ''
if(len(ltrim(rtrim(@sort))) > 0)
SET @sortBy = ' Order By ' + @sort
-- Total Rows Count
SET @sql = 'SELECT Count(' + @strID + ') FROM ' + @strFROM + @strFilter
EXEC sp_executesql @sql
--// This technique is used in a Single Table pagination
SET @sql = 'SELECT ' + @strFields + ' FROM ' + @strFROM +
' WHERE ' + @strID + ' IN ' +
' (SELECT TOP ' + @strPageSize + ' ' + @strID + ' FROM ' + @strFROM + @strFilter +
' AND ' + @strID + ' NOT IN ' + '
(SELECT TOP ' + @strSkippedRows + ' ' + @strID + ' FROM ' + @strFROM + @strFilter + @SortBy + ') '
+ @SortBy + ') ' + @SortBy
Print @sql
EXEC sp_executesql @sql
La meilleure partie est que sp_executesql met en cache les appels ultérieurs, à condition de transmettre les mêmes paramètres, c'est-à-dire de générer le même texte SQL.
CREATE view vw_sppb_part_listsource as
select row_number() over (partition by sppb_part.init_id order by sppb_part.sppb_part_id asc ) as idx, * from (
select
part.SPPB_PART_ID
, 0 as is_rev
, part.part_number
, part.init_id
from t_sppb_init_part part
left join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
where prev.SPPB_PART_ID is null
union
select
part.SPPB_PART_ID
, 1 as is_rev
, prev.part_number
, part.init_id
from t_sppb_init_part part
inner join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
) sppb_part
redémarrera idx en ce qui concerne les différents init_id
Pour la ROW_NUMBER
technique, si vous n'avez pas de colonne de tri à utiliser, vous pouvez utiliser les éléments CURRENT_TIMESTAMP
suivants:
SELECT TOP 20
col1,
col2,
col3,
col4
FROM (
SELECT
tbl.col1 AS col1
,tbl.col2 AS col2
,tbl.col3 AS col3
,tbl.col4 AS col4
,ROW_NUMBER() OVER (
ORDER BY CURRENT_TIMESTAMP
) AS sort_row
FROM dbo.MyTable tbl
) AS query
WHERE query.sort_row > 10
ORDER BY query.sort_row
Cela a bien fonctionné pour moi pour les recherches sur des tailles de table allant jusqu'à 700 000.
Cela récupère les enregistrements 11 à 30.
create PROCEDURE SP_Company_List (@pagesize int = -1 ,@pageindex int= 0 ) > AS BEGIN SET NOCOUNT ON; select Id , NameEn from Company ORDER by Id ASC OFFSET (@pageindex-1 )* @pagesize ROWS FETCH NEXt @pagesize ROWS ONLY END GO
DECLARE @return_value int EXEC @return_value = [dbo].[SP_Company_List] @pagesize = 1 , > @pageindex = 2 SELECT 'Return Value' = @return_value GO
Ce bit vous donne la possibilité de paginer à l'aide de SQL Server et des versions plus récentes de MySQL et porte le nombre total de lignes dans chaque ligne. Utilise votre clé pimary pour compter le nombre de lignes uniques.
WITH T AS
(
SELECT TABLE_ID, ROW_NUMBER() OVER (ORDER BY TABLE_ID) AS RN
, (SELECT COUNT(TABLE_ID) FROM TABLE) AS TOTAL
FROM TABLE (NOLOCK)
)
SELECT T2.FIELD1, T2.FIELD2, T2.FIELD3, T.TOTAL
FROM TABLE T2 (NOLOCK)
INNER JOIN T ON T2.TABLE_ID=T.TABLE_ID
WHERE T.RN >= 100
AND T.RN < 200
Ceci est un double de l'ancienne question SO 2012: un moyen efficace de mettre en œuvre la pagination
À PARTIR DE [TableX] COMMANDER PAR [FieldX] OFFSET 500 RANGS FETCH NEXT 100 ROWS ONLY
Ici, le sujet est discuté plus en détail et avec des approches alternatives.
Vous n'avez pas spécifié la langue ni le pilote que vous utilisez. Je le décris donc de manière abstraite.