Как ссылаться на один CTE дважды? - PullRequest
25 голосов
/ 26 января 2010

У меня очень толстое общее табличное выражение, которое включает номера строк, чтобы я мог вернуть постраничный набор результатов. Я также хочу вернуть общее количество записей, которые соответствуют запросу, прежде чем пейджировать набор результатов.

with recs as (select *, row_number() over (order by id) as rownum from ......)
select * from recs where rownum between @a and @b .... select count(*) from recs

Очевидно, что мой запрос выше неоднозначен, но он просто для иллюстрации моей точки зрения. Я хочу страницу результатов И общее количество матчей. Как мне сделать это без необходимости буквально копировать и вставлять целую строку 20+ CTE?

Ответы [ 5 ]

19 голосов
/ 26 января 2010

Вы можете использовать запятые для создания нескольких CTE, которые ссылаются на CTE выше.

Просто чтобы проиллюстрировать, что я имею в виду:

with recs as (
select 
    *, 
    row_number() over (order by id) as rownum from ......
    ),
counts as (
    select count(*) as totalrows from recs
)
select recs.*,count.totalrows
from recs
cross apply counts 
where rownum between @a and @b .... 

Это не очень хорошее решение.

Лучшее решение, которое я нашел для общего подсчета в CTE без учета записей, описано в этой статье .

DECLARE @startRow INT; SET @startrow = 50;
WITH cols
AS
(
    SELECT table_name, column_name, 
        ROW_NUMBER() OVER(ORDER BY table_name, column_name) AS seq, 
        ROW_NUMBER() OVER(ORDER BY table_name DESC, column_name desc) AS totrows
    FROM [INFORMATION_SCHEMA].columns
)
SELECT table_name, column_name, totrows + seq -1 as TotRows
FROM cols
WHERE seq BETWEEN @startRow AND @startRow + 49
ORDERBY seq
19 голосов
/ 26 января 2010

Не думай, что сможешь.С MSDN

Общее табличное выражение (CTE) можно рассматривать как временный набор результатов, который определен в пределах области выполнения одного SELECT, INSERT, UPDATE, DELETE.или CREATE VIEW.

Акцент на «одном операторе SELECT, INSERT, UPDATE, DELETE или CREATE VIEW.»

Это может быть ситуация, когда вы хотите использовать Временная таблица .

CREATE TABLE #Recs
{
  .....
}
INSERT INTO #Recs
select *, row_number() over (order by id) as rownum from ......

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

select *, row_number() over (order by id) as rownum INTO #Recs from ......

Вы сможете использовать Временную таблицу так, как описано выше.

4 голосов
/ 02 августа 2012

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

select recs.*,totalrows = (select count(0) from recs) 
from recs
1 голос
/ 24 января 2017

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

DECLARE
   @p_PageNumberRequested  int = 1,
      -- Provide -1 to retreive all pages with all the rows.
   @p_RowsPerPage          int = 25

;WITH Numbered AS (
SELECT
   ROW_NUMBER() OVER (ORDER BY YourOrdering) AbsoluteRowNumber
,  COUNT(1) OVER () TotalRows
,  YourColumns
FROM
   YourTable
),
Paged AS (
SELECT
   (AbsoluteRowNumber - 1) / @p_RowsPerPage + 1 PageNumber,
   *
FROM
   Numbered)
SELECT
   ROW_NUMBER() OVER(PARTITION BY PageNumber ORDER BY AbsoluteRowNumber) RowNumberOnPage,
   *
FROM
   Paged
WHERE
      PageNumber = @p_PageNumberRequested
   OR
      @p_PageNumberRequested = -1
ORDER BY 
   AbsoluteRowNumber
1 голос
/ 27 апреля 2016

Это лучшее:

;WITH recs AS
(SELECT a,b,c,
      row_number() over (
                         ORDER BY id) AS RowNum,
                   row_number() over () AS RecordCount
FROM ......)
SELECT a,b,c,rownum,RecordCount FROM recs
WHERE rownum BETWEEN @a AND @b
...