Лучший способ получить общее количество записей с помощью SQL Query при подкачке данных

Я отображаю данные на странице, которая содержит 15 строк на странице. Я использую ключевые слова OFFSET и FETCH SQL Server 2012, чтобы ограничить 15 строк, которые мне нужны. Однако я хочу отобразить ОБЩЕЕ количество доступных строк, как мне это сделать в одном запросе?

Например, вверху страницы вы просматриваете 15 из 1505 записей.

Есть ли способ объединить это с моим существующим запросом?


person Pearce    schedule 27.11.2013    source источник
comment
Я разрешил этот конкретный сценарий, используя SQLDataReader и запросив две отдельные таблицы. Одна таблица для 15 записей, затем еще один запрос с использованием функции Count() для вызова общего количества записей.   -  person Pearce    schedule 27.11.2013


Ответы (3)


Как продемонстрировали другие, вы можете это сделать, но вместо того, чтобы использовать COUNT, как они демонстрируют, я собираюсь использовать системные метаданные, которые чертовски быстрее. Физически вызов SELECT COUNT(1) AS rc FROM MyTable заставит подсистему хранения перебрать все данные, которые могут быть или не быть в памяти, чтобы выполнить подсчет и дождаться разблокировки любых монопольных блокировок.

Знаете, что эффективнее? Просто глядя на sys.allocation_units.

SELECT
    s.[Name] as [Schema] 
,   t.[name] as [Table] 
,   SUM(p.rows) as [RowCount] 
FROM
    sys.schemas s 
    LEFT OUTER JOIN 
        sys.tables t 
        ON s.schema_id = t.schema_id 
    LEFT OUTER JOIN 
        sys.partitions p 
        ON t.object_id = p.object_id 
    LEFT OUTER JOIN  
        sys.allocation_units a 
        ON p.partition_id = a.container_id 
WHERE
    p.index_id  in(0,1) -- 0 heap table , 1 table with clustered index 
    AND p.rows is not null
    AND a.type = 1  -- row-data only , not LOB 
GROUP BY 
    s.[Name] 
,   t.[name] 
ORDER BY 
    1 
,   2; 

h/t bimonkey за его сообщение Мгновенно подсчитайте количество строк в каждой таблице базы данных!

Если вам нужен «одиночный» запрос, который делает это, вам нужно объединить вышеуказанное с вашим смещением и выборкой.

В SQL не обманывайте себя, приравнивая меньшее количество строк кода к меньшей сложности или лучшей производительности.

Я аннотировал следующий запрос, так как он действительно довольно прост.

-- Create variables for our usage
-- http://technet.microsoft.com/en-us/library/ms188927.aspx
DECLARE @OFFSET int = 30
,   @FETCH int = 15;

-- Notice the previous statement ends with a semicolon (;)
-- The following structure is a Common Table Expression (CTE)
-- Think of it as a single use View
-- http://technet.microsoft.com/en-us/library/ms190766(v=sql.105).aspx
WITH COUNTS AS
(
    -- This query provides the number of rows in all the tables
    -- in the current catalog. It is screaming cheetah wheelies fast 
    -- as it does not need to physically read each row from each table
    -- to generate counts. Instead, it is using system metadata to 
    -- derive the row count.
    -- After the closing ), I will have access to a tabular structure
    -- called COUNTS 
    SELECT
        s.[Name] as [Schema] 
    ,   t.[name] as [Table] 
    ,   SUM(p.rows) as [RowCount] 
    FROM
        -- http://technet.microsoft.com/en-us/library/ms176011.aspx
        sys.schemas s 
        LEFT OUTER JOIN 
            -- http://technet.microsoft.com/en-us/library/ms187406.aspx
            sys.tables t 
            ON s.schema_id = t.schema_id 
        LEFT OUTER JOIN 
            -- http://technet.microsoft.com/en-us/library/ms175012.aspx
            sys.partitions p 
            ON t.object_id = p.object_id 
        LEFT OUTER JOIN  
            -- http://technet.microsoft.com/en-us/library/ms189792.aspx
            sys.allocation_units a 
            ON p.partition_id = a.container_id 
    WHERE
        p.index_id  in(0,1) -- 0 heap table , 1 table with clustered index 
        AND p.rows is not null
        AND a.type = 1  -- row-data only , not LOB 
    GROUP BY 
        s.[Name] 
    ,   t.[name] 
)
SELECT
    T.*
,   @OFFSET AS StartingRow
,   @FETCH AS PageSize
-- A subquery that uses the CTE above to extract our table's total row count
-- The table and schema below must align with the value in your FROM clause
-- http://technet.microsoft.com/en-us/library/ms189575(v=sql.105).aspx
,   (SELECT C.[RowCount] FROM COUNTS C WHERE C.[schema] = 'dbo' AND C.[Table] = 'MyTable') AS TotalRows
FROM
    dbo.MyTable T
ORDER BY
    1
-- http://technet.microsoft.com/en-us/library/gg699618.aspx    
OFFSET 30 ROWS
FETCH NEXT 15 ROWS ONLY;
person billinkc    schedule 27.11.2013
comment
Спасибо за ваш совет. Ваш запрос взорвал мне мозг, поэтому я выбрал метод подсчета, но приятно знать, что есть более эффективный способ вместо подсчета, когда он мне действительно нужен. - person Pearce; 27.11.2013

Для тех, кто использует SQL Server 10.50, я могу сделать это, используя наборы результатов с помощью Common Table Expressions (CTE). Что-то вроде этого:

WITH resultSet AS     
(
SELECT 
   ROW_NUMBER() OVER(ORDER BY x.ID DESC) as Row, 
   x.other_fields
   FROM Table x    
   WHERE conditions_x
),
cte AS
(
   SELECT TOP 1 Row AS cte_row FROM resultSet ORDER BY Row DESC
)
-- And finally:
SELECT cte.cte_row AS Total, * FROM resultSet CROSS JOIN cte 
WHERE Row BETWEEN 11 AND 20; -- Rows between 11 and 20, for example. Those would be your previously computed START and END row variables.

Это должно работать как один запрос.

Я не пробовал это в SQL Server 2012, но думаю, что это тоже может сработать.

person Marco    schedule 15.01.2020

Вы можете использовать COUNT():

SELECT COUNT(*) FROM Table
WHERE conditionHere

А затем количество страниц, которое вы должны сделать на выбранном вами языке программирования, будь то, например, php или asp.net.

И в основном вычисления выглядят так:

PageNumber * RecordsPerPage

Допустим, номер страницы 2 с 15 записями на странице будет таким:

2 * 15

Итак, ваш вывод будет

30 of NumberOfRecords

Вы могли бы посчитать, как страницы, используя формулу

TotalPages = CEILING(TotalRecords / RecordsPerPages)

Например, используя ваши собственные цифры, это будет:

TotalPages = CEILING(1,505 / 15)

Что составляет 101, если вы получите максимальное значение.

Если бы Php это, вероятно, выглядело бы так:

$TotalPages = Ceil($NumberOfRecords / $RecordsPerPages)

Если бы ASP использовал C#, это, вероятно, выглядело бы так:

int TotalPages = Math.Ceil(NumberOfRecords/RecordsPerPages);

Однако, если они облизывают последнюю страницу, на которую нажали, вы можете просто сказать:

TotalRecords of TotalRecords

Например:

1,505 of 1,505
person Edper    schedule 27.11.2013