ما هي أفضل طريقة لترقيم الصفحات النتائج في SQL Server

StackOverflow https://stackoverflow.com/questions/109232

سؤال

ما هي أفضل طريقة (من حيث الأداء) لترقيم الصفحات النتائج في SQL Server 2000، 2005، 2008، 2012 إذا كنت تريد أيضًا الحصول على العدد الإجمالي للنتائج (قبل ترقيم الصفحات)؟

هل كانت مفيدة؟

المحلول

الحصول على العدد الإجمالي للنتائج وترقيم الصفحات هما عمليتان مختلفتان.من أجل هذا المثال، لنفترض أن الاستعلام الذي تتعامل معه هو

SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate

في هذه الحالة، يمكنك تحديد العدد الإجمالي للنتائج باستخدام:

SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'

... والتي قد تبدو غير فعالة، ولكنها في الواقع ذات أداء جيد، مع افتراض جميع الفهارس وما إلى ذلك.تم إعدادها بشكل صحيح.

بعد ذلك، للحصول على النتائج الفعلية مرة أخرى بطريقة مقسمة إلى صفحات، سيكون الاستعلام التالي أكثر فعالية:

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

سيؤدي هذا إلى إرجاع الصفوف من 1 إلى 19 من الاستعلام الأصلي.الشيء الرائع هنا، خاصة بالنسبة لتطبيقات الويب، هو أنك لست مضطرًا إلى الاحتفاظ بأي حالة، باستثناء أرقام الصفوف التي سيتم إرجاعها.

نصائح أخرى

أخيراً، مايكروسوفت SQL خادم 2012 تم إصداره، وأنا حقًا أحب بساطته بالنسبة إلى ترقيم الصفحات، فلا يتعين عليك استخدام الاستعلامات المعقدة مثل الإجابة هنا.

للحصول على الصفوف العشرة التالية، قم فقط بتشغيل هذا الاستعلام:

SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

http://technet.microsoft.com/en-us/library/gg699618.aspx

النقاط الرئيسية التي يجب مراعاتها عند استخدامه:

  • ORDER BY إلزامي لاستخدام عبارة OFFSET وFETCH.
  • شرط OFFSET إلزامي مع FETCH.لا يمكنك أبدًا استخدام ، طلب ... جلب.
  • لا يمكن دمج الأعلى مع الإزاحة وجلبه في نفس التعبير عن الاستعلام.

بشكل لا يصدق، لم تذكر أي إجابة أخرى الأسرع طريقة عمل ترقيم الصفحات في كافة إصدارات SQL Server.يمكن أن تكون الإزاحات بطيئة للغاية بالنسبة لأعداد الصفحات الكبيرة كما هي قياسا هنا.هناك طريقة مختلفة تمامًا وأسرع بكثير لتنفيذ ترقيم الصفحات في SQL.يُطلق على هذا غالبًا اسم "طريقة البحث" أو "ترقيم الصفحات لمجموعة المفاتيح" كما هو موضح في هذا بلوق وظيفة هنا.

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

"مسند البحث"

ال @previousScore و @previousPlayerId القيم هي القيم الخاصة بالسجل الأخير من الصفحة السابقة.يتيح لك ذلك جلب الصفحة "التالية".إذا ORDER BY الاتجاه هو ASC, ، استخدم ببساطة > بدلاً من.

باستخدام الطريقة المذكورة أعلاه، لا يمكنك الانتقال فورًا إلى الصفحة 4 دون جلب السجلات الأربعين السابقة أولاً.لكن في كثير من الأحيان، لا ترغب في القفز إلى هذا الحد على أي حال.بدلاً من ذلك، ستحصل على استعلام أسرع بكثير قد يكون قادرًا على جلب البيانات في وقت ثابت، اعتمادًا على الفهرسة الخاصة بك.بالإضافة إلى ذلك، تظل صفحاتك "مستقرة"، بغض النظر عما إذا كانت البيانات الأساسية قد تغيرت (على سبيل المثال.في الصفحة 1، بينما أنت في الصفحة 4).

هذه هي أفضل طريقة لتنفيذ ترقيم الصفحات عند التحميل البطيء لمزيد من البيانات في تطبيقات الويب، على سبيل المثال.

لاحظ أن "طريقة البحث" تسمى أيضًا ترقيم الصفحات مجموعة المفاتيح.

إجمالي السجلات قبل ترقيم الصفحات

ال COUNT(*) OVER() ستساعدك وظيفة النافذة على حساب إجمالي عدد السجلات "قبل ترقيم الصفحات".إذا كنت تستخدم SQL Server 2000، فسيتعين عليك اللجوء إلى استعلامين لـ COUNT(*).

من SQL Server 2012، يمكننا استخدام OFFSET و FETCH NEXT بند لتحقيق ترقيم الصفحات.

جرب هذا لـ SQL Server:

في SQL Server 2012 ، تمت إضافة ميزة جديدة بالترتيب عن طريق الجملة ، للاستعلام عن تحسين البيانات المحددة ، مما يجعل العمل أسهل مع ترحيل البيانات لأي شخص يكتب في T-SQL وكذلك لخطة التنفيذ بأكملها في SQL Server.

أسفل البرنامج النصي T-SQL مع نفس المنطق المستخدم في المثال السابق.

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

تكنيت:ترحيل استعلام مع SQL Server

هناك نظرة عامة جيدة على تقنيات الترحيل المختلفة في http://www.codeproject.com/KB/aspnet/PagingLarge.aspx

لقد استخدمت طريقة ROWCOUNT في كثير من الأحيان مع SQL Server 2000 (ستعمل مع 2005 و 2008 أيضًا، ما عليك سوى قياس الأداء مقارنةً بـ ROW_NUMBER)، إنها سريعة جدًا، ولكنك تحتاج إلى التأكد من أن الأعمدة (الأعمدة) التي تم فرزها بها (في الغالب) ) القيم الفريدة.

شبكة MSDN:ROW_NUMBER (Transact-SQL)

إرجاع الرقم التسلسلي لصف داخل قسم من مجموعة النتائج، بدءًا من 1 للصف الأول في كل قسم.

يقوم المثال التالي بإرجاع صفوف تحتوي على أرقام من 50 إلى 60 ضمناً بترتيب 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

بالنسبة لـ SQL Server 2000، يمكنك محاكاة ROW_NUMBER() باستخدام متغير جدول بعمود 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

يمكن توسيع هذا الأسلوب ليشمل الجداول التي تحتوي على مفاتيح متعددة الأعمدة، ولا يتحمل عبء الأداء الناتج عن استخدام OR (الذي يتخطى استخدام الفهرس).الجانب السلبي هو مقدار المساحة المؤقتة المستخدمة إذا كانت مجموعة البيانات كبيرة جدًا وكانت إحداها قريبة من الصفحة الأخيرة.لم أختبر أداء المؤشر في هذه الحالة، لكنه قد يكون أفضل.

لاحظ أنه يمكن تحسين هذا الأسلوب للصفحة الأولى من البيانات.كما تم استخدام ROWCOUNT نظرًا لأن TOP لا يقبل متغيرًا في SQL Server 2000.

أفضل طريقة للترحيل في SQL Server 2012 هي استخدام الإزاحة والجلب التالي في الإجراء المخزن.إزاحة الكلمة الرئيسية - إذا استخدمنا الإزاحة بالترتيب حسب الجملة، فسيتخطى الاستعلام عدد السجلات التي حددناها في OFFSET n Rows.

جلب الكلمات الرئيسية التالية - عندما نستخدم Fetch Next مع ترتيب حسب الجملة فقط، فإنه سيُرجع عدد الصفوف التي تريد عرضها في الترحيل، وبدون الإزاحة، سيُنشئ SQL خطأً.هنا هو المثال الوارد أدناه.

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

يمكنك تنفيذه على النحو التالي.

exec sp_paging 2,3

هذه هي الحلول الخاصة بي لترحيل نتيجة الاستعلام في جانب خادم SQL.تختلف هذه الأساليب بين SQL Server 2008 و2012.كما قمت بإضافة مفهوم التصفية والترتيب بعمود واحد.إنه فعال للغاية عند الترحيل والتصفية والطلب في Gridview الخاص بك.

قبل الاختبار، عليك إنشاء جدول نموذجي واحد وإدراج بعض الصفوف في هذا الجدول:(في العالم الحقيقي، يتعين عليك تغيير عبارة Where مع الأخذ في الاعتبار حقول الجدول الخاص بك وربما يكون لديك بعض عمليات الانضمام والاستعلام الفرعي في الجزء الرئيسي من التحديد)

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

في كل هذه العينات، أريد الاستعلام عن 200 صف لكل صفحة وأقوم بإحضار الصف للصفحة رقم 1200.

في SQL Server 2008، يمكنك استخدام مفهوم CTE.ولهذا السبب، قمت بكتابة نوعين من الاستعلامات لـ SQL server 2008+

- SQL خادم 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

والحل الثاني مع CTE في خادم SQL 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 خادم 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;

جرب هذا النهج:

SELECT TOP @offset a.*
FROM (select top @limit b.*, COUNT(*) OVER() totalrows 
        from TABLENAME b order by id asc) a
ORDER BY id desc;

يبدو أن استخدام الحالة الحكيمة سهل الاستخدام وسريع، فقط قم بتعيين رقم الصفحة.

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)

أيضا مع 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)

حسنًا، لقد استخدمت نموذج الاستعلام التالي في قاعدة بيانات SQL 2000 الخاصة بي، وهو يعمل بشكل جيد مع SQL 2005 أيضًا.القوة التي توفرها لك هي أمر ديناميكي باستخدام أعمدة متعددة.أقول لكم ...هذا قوي :)

    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

أفضل جزء هو أن sp_executesql يقوم بالتخزين المؤقت للمكالمات اللاحقة، بشرط أن تقوم بتمرير نفس المعلمات، أي إنشاء نفس نص 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

سيتم إعادة تشغيل idx عندما يتعلق الأمر بـ init_id مختلف

ل ROW_NUMBER التقنية، إذا لم يكن لديك عمود فرز لاستخدامه، فيمكنك استخدام CURRENT_TIMESTAMP على النحو التالي:

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

لقد نجح هذا الأمر جيدًا بالنسبة لي في عمليات البحث على جداول بأحجام تصل إلى 700000.

يؤدي هذا إلى جلب السجلات من 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

يمنحك هذا الجزء القدرة على ترقيم الصفحات باستخدام SQL Server والإصدارات الأحدث من MySQL ويحمل إجمالي عدد الصفوف في كل صف.يستخدم مفتاحك الأساسي لحساب عدد الصفوف الفريدة.

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

لم تحدد اللغة ولا برنامج التشغيل الذي تستخدمه.لذلك أنا أصف ذلك بشكل تجريدي.

  • قم بإنشاء مجموعة نتائج/مجموعة بيانات قابلة للتمرير.هذا يتطلب أساسيًا على الجدول (الجداول)
  • القفز حتى النهاية
  • طلب عدد الصفوف
  • انتقل إلى بداية الصفحة
  • قم بالتمرير عبر الصفوف حتى نهاية الصفحة
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top