web-dev-qa-db-ja.com

ページング中に合計行数を取得する

ユーザーが5つのフィルターで検索できる検索画面があります。
これらのフィルター値に基づいて動的クエリを作成し、一度に10ページの結果を取得しました。
これはOFFSETFETCHを使用してSQL2012で正常に機能していますが、twoを使用しています=これを行うクエリ。

10個の結果を表示し、クエリで見つかった行の総数を表示します(たとえば、1000としましょう)。
現在、私はクエリtwiceを実行することでこれを行っています-合計カウントに対して1回、次に10行をページングするためにもう一度。
これを行うためのより効率的な方法はありますか?

16
user788312

クエリを2回実行する必要はありません。

_SELECT ..., total_count = COUNT(*) OVER()
FROM ...
ORDER BY ...
OFFSET 120 ROWS
FETCH NEXT 10 ROWS ONLY;
_

the chat に基づくと、問題は少し複雑になっているようです。ページングに加えて、結果にDISTINCTを適用しています。これは、COUNT()がどのように見えるべきか、どこに行くべきかを正確に決定することを複雑にする可能性があります。ここに1つの方法があります(チャットからのはるかに複雑なクエリにこの手法を組み込むのではなく、これをデモンストレーションしたいだけです)。

_USE tempdb;
GO
CREATE TABLE dbo.PagingSample(id INT,name SYSNAME);

-- insert 20 rows, 10 x 2 duplicates
INSERT dbo.PagingSample SELECT TOP (10) [object_id], name FROM sys.all_columns;
INSERT dbo.PagingSample SELECT TOP (10) [object_id], name FROM sys.all_columns;

SELECT COUNT(*) FROM dbo.PagingSample; -- 20

SELECT COUNT(*) FROM (SELECT DISTINCT id, name FROM dbo.PagingSample) AS x; -- 10

SELECT DISTINCT id, name FROM dbo.PagingSample; -- 10 rows

SELECT DISTINCT id, name, COUNT(*) OVER() -- 20 (DISTINCT is not computed yet)
 FROM dbo.PagingSample
 ORDER BY id, name
 OFFSET (0) ROWS FETCH NEXT (5) ROWS ONLY; -- 5 rows

-- this returns 5 rows but shows the pre- and post-distinct counts:
SELECT PostDistinctCount = COUNT(*) OVER() -- 10, 
  PreDistinctCount -- 20, 
  id, name 
FROM 
(
  SELECT DISTINCT id, name, PreDistinctCount = COUNT(*) OVER() 
    FROM dbo.PagingSample
    -- INNER JOIN ...
) AS x
ORDER BY id, name
OFFSET (0) ROWS FETCH NEXT (5) ROWS ONLY;
_

掃除:

_DROP TABLE dbo.PagingSample;
GO
_
25
Aaron Bertrand

私の解決策は「rs。答え」に似ています

DECLARE @PageNumber AS INT, @RowspPage AS INT
SET @PageNumber = 2
SET @RowspPage = 5 

SELECT   COUNT(*) OVER() totalrow_count,*
    FROM databasename
    where columnname like '%abc%'
    ORDER BY columnname
    OFFSET ((@PageNumber - 1) * @RowspPage) ROWS
    FETCH NEXT @RowspPage ROWS ONLY;

返される結果には、最初の列名としてtotalrow_countが含まれます

3
Sarah Filano

このようなことを試すことができますか

SELECT TOP 10 * FROM 
(
   SELECT COUNT(*) OVER() TOTALCNT, T.*
   FROM TABLE1 T
   WHERE col1 = 'somefilter'
) v

または

SELECT * FROM 
(
   SELECT COUNT(*) OVER() TOTALCNT, T.*
   FROM TABLE1 T
   WHERE col1 = 'somefilter'
) v
ORDER BY COL1
OFFSET 0 ROWS FETCH FIRST 10 ROWS ONLY

これで、totalcnt列に合計数が表示され、この列を使用して行の総数を表示できます

3
rs.

私がこの質問に飛び込むのに遅すぎないことを願っていますが、今夜は非常によく似た問題に遭遇しました。以前の開発者がDISTINCTを削除し、テーブル結合のSELECT count(*)を実行しただけだったため、返された結果の数を大幅に増やしているページングクラスがありました。これは2つのクエリの問題を解決しませんが、次のようにネストされたクエリを使用することになりました。

元のクエリ

SELECT DISTINCT
  field1, field2
FROM
  table1 t1
  left join table2 t2 on t2.id = t1.id

膨張した結果クエリ

SELECT
  count(*)
FROM
  table1 t1
  left join table2 t2 on t2.id = t1.id

私の結果クエリソリューション

SELECT
  count(*)
FROM
  (SELECT DISTINCT
     field1, field2
   FROM
     table1 t1
     left join table2 t2 on t2.id = t1.id) as tbl;
1
David