Який найкращий спосіб додати результати пошуку на SQL Server


474

Який найкращий спосіб (залежно від продуктивності) підкреслити результати в SQL Server 2000, 2005, 2008, 2012, якщо ви також хочете отримати загальну кількість результатів (перед тим, як створити сторінку)?


26
Мені завжди було цікаво, чому вони не просто підтримують вказівку зміщення як частини TOP (як підтримка MySQL / Posgresql з LIMIT / OFFSET). Наприклад, вони могли просто мати синтаксис "ВИБІР ТОП х, у ....", де х = кількість рядків, у = початкове зміщення. Це також було б сумісним назад.
gregmac

3
Гей, я теж ... реалізація сторінки в рамках сторінки, що
склалася

6
@gregmac - Сервер Sql 2012 зараз має обмеження / зміщення.
OO

2
Прийняте рішення не показує, наскільки це найкращий спосіб (ефективність роботи). Будь-які дані, які створюють резервну копію на великих наборах даних?
OO

3
@OO: Хороший орієнтир можна знайти тут: 4guysfromrolla.com/webtech/042606-1.shtml . Однак метод пошуку випереджає будь-яку розбиття на основі зміщення.
Лукас Едер

Відповіді:


465

Отримання загальної кількості результатів та пагинація - це дві різні операції. Заради цього прикладу припустимо, що запит, з яким ви маєте справу, є

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 початкового запиту. Найзручніша річ, особливо для веб-додатків, - це те, що вам не потрібно зберігати будь-який стан, крім номерів рядків, які потрібно повернути.


37
Зауважимо лише, що ROW_NUMBER () не існує в SQL Server 2000
Джон Хантер

6
повертає це всі рядки з внутрішнього запиту та потім фільтрує на основі зовнішнього запиту? наприклад: внутрішній запит повертає 100 000, а зовнішній запит повертає лише 20.
SoftwareGeek

2
@SoftwareGeek: розгляньте це як підзапит (внутрішній запит), що повертає потік, який потім читається, поки не буде задоволено зовнішній пункт WHERE. Як рядки можуть бути пов’язані з цим, повністю залежить від запиту, але оптимізатор, як правило, робить дуже гарну роботу щодо мінімізації цього числа. Використання програми перегляду графічного плану виконання у студії управління SQL Server (використовуйте Запит / Включити фактичний план виконання) є дуже навчальним у цьому плані.
mdb

2
добре, що робити, якщо вас дублюють у внутрішньому виділенні (наприклад, коли у вас є внутрішній приєднання), як ви використовуєте чітку, оскільки RowNumber відрізняється, і це не працює
user217648

10
Microsoft додала нову функцію до SQL 2012, яка робить сторінки на сторінці, схожі на MySQL. Перейдіть за цим посиланням, щоб дізнатися, як це зробити. Цікава стаття: dbadiaries.com/…
Араш

511

Нарешті, був випущений Microsoft SQL Server 2012 , мені дуже подобається його простота для створення сторінки, вам не доведеться використовувати складні запити, як тут відповіли.

Для отримання наступних 10 рядків просто запустіть цей запит:

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

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql#using-offset-and-fetch-to-limit-the-rows- повернувся

Основні моменти, які слід враховувати при його використанні:

  • ORDER BYобов'язкове використання OFFSET ... FETCHпункту.
  • OFFSETпункт обов'язковий з FETCH. Ви не можете використовувати ORDER BY ... FETCH.
  • TOPне може поєднуватися з OFFSETі FETCHтим самим виразом запиту.

12
Ще чекаю на LISTAGG()/ GROUP_CONCAT().
Беконові шматочки

1
@BaconBits Дивіться цей відповідь на підлий спосіб зробити це з FOR XML: stackoverflow.com/a/273330/429949
Річард Marskell - Drackir

1
@ RichardMarskell-Drackir З цим багато проблем FOR XML PATH (''). По-перше, він замінює символи керування XML кодами сутності XML. Сподіваюся , що у вас немає <, >або &в ваших даних! По-друге, FOR XML PATH ('')використаний таким чином насправді недокументований синтаксис. Ви повинні вказати іменний стовпець або альтернативне ім’я елемента. Виконання жодного з них не є в документі, тобто поведінка є ненадійною. По-третє, чим більше ми приймаємо розбитий FOR XML PATH ('')синтаксис, тим менше ймовірність, що MS насправді забезпечує реальну LISTAGG() [ OVER() ] функцію, як їм потрібно.
Шматочки бекону

4
ганьба перфорація так погано mssqlgirl.com / ...
Jon

5
@Jon, що пов’язана публікація в блозі не є репрезентативною, в тому сенсі вона проводить порівняння на основі повернення результату сторінки шляхом пошуку значень стовпця id.
Ноель Абрахамс

103

Неймовірно, що жодна інша відповідь не згадала про найшвидший спосіб зробити пагінацію у всіх версіях 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, попередньо не отримавши попередніх 40 записів. Але часто вам так і не хочеться стрибати так далеко. Натомість ви отримуєте набагато швидший запит, який може отримати дані за постійний час, залежно від вашої індексації. Крім того, ваші сторінки залишаються "стабільними", незалежно від того, чи змінюються основні дані (наприклад, на сторінці 1, поки ви перебуваєте на сторінці 4).

Це найкращий спосіб реалізувати сторінки, якщо ледаче завантажувати більше даних у веб-додатки.

Зауважте, "метод пошуку" також називається розбиттям клавіш .

Всього записів до пагинації

Функція COUNT(*) OVER()вікна допоможе вам підрахувати кількість загальних записів "до пагинації". Якщо ви використовуєте SQL Server 2000, вам доведеться вдатися до двох запитів для COUNT(*).


2
@ user960567: З точки зору продуктивності, підказка на клавіатурі завжди перемагатиме зміщення підкачки, незалежно від того, застосовуєте ви підкачки зсуву зі стандартом SQL OFFSET .. FETCHабо попередніми ROW_NUMBER()підказками.
Лукаш Едер

21
У мене є три питання з методом пошуку. [1] Користувач не може перейти на сторінку. [2] він передбачає послідовні ключі, тобто якщо хтось видаляє 3 рядки, то я отримую сторінку з 7 елементів замість 10. RowNumberдає мені 10 послідовних елементів на сторінку. [3] він не працює з існуючими сітками, які припускають pagenumberі pagesize.
Ребекка

7
@Junto: підказка на клавіатурі не підходить для всіх випадків. Це точно не для сіток даних. Але він ідеально підходить для таких сценаріїв, як нескінченна прокрутка сторінки стрічки Facebook. Неважливо, чи додаються нові публікації вгорі, ваші наступні публікації каналів будуть правильно додані донизу, коли ви прокручуєте вниз. Ідеальний приклад використання для цього ... Таку річ було б набагато важче реалізувати, використовуючи обмеження зсуву / отримання лише з використанням чисел.
Роберт Коритник

4
Я повинен погодитися з Донто. Цей метод повністю виключає клієнта, який має досить стандартний інтерфейс сторінки з "Попередній 1 2 3 (4) 5 6 Далі", де користувачі можуть стрибати вперед. Це не зовсім
кращий

3
Стаття про пагінацію клавіатури тут
Stphane

31

З SQL Server 2012 ми можемо використовувати OFFSETта FETCH NEXTдодаток для досягнення сторінки.

Спробуйте це для SQL Server:

У пункті ORDER BY в 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;

TechNet: підключення запиту до SQL Server


найточніша відповідь у цьому випробуванні
Вікрант

17

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

15

На веб- сайті http://www.codeproject.com/KB/aspnet/PagingLarge.aspx є хороший огляд різних методів підкачки.

Я досить часто використовував метод ROWCOUNT в основному з SQL Server 2000 (також буде працювати з 2005 та 2008 роками, просто виміряйте ефективність порівняно з ROW_NUMBER), це блискавично, але вам потрібно переконатися, що впорядковані стовпці (стовпці) є (в основному ) унікальні значення.


1
Цікаво, що ця стаття не згадує метод пошуку , який здатний виконувати пейджингові роботи в постійний час ... Ще хороша стаття
Лукас Едер

6

Для 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

Цей підхід можна поширити на таблиці з клавішами з декількома стовпцями, і він не несе накладні витрати на використання АБО (що пропускає використання індексу). Недоліком є ​​кількість використаного тимчасового простору, якщо набір даних дуже великий і один знаходиться біля останньої сторінки. Я не перевіряв продуктивність курсора в цьому випадку, але це може бути краще.

Зауважте, що цей підхід можна оптимізувати для першої сторінки даних. Також ROWCOUNT використовувався, оскільки TOP не приймає змінну в SQL Server 2000.


3

Найкращий спосіб підкачки на сервері sql 2012 - це використання зсуву та отримання наступного в збереженій процедурі. Ключове слово OFFSET - Якщо ми будемо використовувати зсув із порядком за пунктом, то запит пропустить кількість записів, які ми вказали в OFFSET n рядках.

ДОСЛІДЖЕННЯ СЛІДКОВИХ ключових слів - Коли ми використовуємо 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

2

Це мої рішення для підкачки результатів запиту на стороні SQL-сервера. ці підходи відрізняються між SQL Server 2008 та 2012 роками. Також я додав концепцію фільтрації та порядку за допомогою одного стовпця. Це дуже ефективно, коли ви шукаєте під час пейджингу, фільтрації та замовлення у своєму Gridview.

Перед тестуванням ви повинні створити одну зразкову таблицю і вставити в цю таблицю якийсь рядок: (У реальному світі ви повинні змінити пункт «Де», враховуючи поля вашої таблиці, і, можливо, у вас є кілька приєднань та підзапитів у головній частині вибору)

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 2008 можна використовувати концепцію CTE. Через це я написав два типи запитів для SQL-сервера 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

І друге рішення з 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 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;

1

Спробуйте такий підхід:

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

1

Використовуйте регістр, наступний, здається, простий у використанні та швидко. Просто встановіть номер сторінки.

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)

1
Що робить, де 1 = 1 робить сер?
Еррол Палеракіо

0

Я використовував наступний зразок запиту в моїй базі даних 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.


0
   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


0

Для 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

Це добре працювало для пошуку в розмірах таблиць навіть до 700 000.

Це отримує записи від 11 до 30.


Як хороша практика, під час пагинації вам слід спробувати замовити унікальний набір стовпців у наборі результатів, оскільки порядок не слід вважати гарантованим.
Арін Тейлор

2
Це результати записів від 11 до 30.
Ардалан Шахголі

0
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

0

Цей біт дає вам можливість пагінації за допомогою 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

Чи можете ви залишити будь-які коментарі, які пояснюють, що робить ваш код?
Doug F


0

З 2012 року ми можемо використовувати OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY


-19

Ви не вказали ні мову, ні драйвер, яким ви користуєтесь. Тому я описую це абстрактно.

  • Створіть прокручуваний набір результатів / набір даних. Для цього потрібна основна таблиця (и)
  • стрибати до кінця
  • запит на кількість рядків
  • перейти до початку сторінки
  • прокручуйте рядки до кінця сторінки
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.