2010-01-26 26 views
24

Tengo una expresión de tabla común muy gruesa que incluye números de fila para que pueda devolver un conjunto de resultados paginado. También quiero devolver el número total de registros que coinciden con la consulta antes de pasar al conjunto de resultados.¿Cómo hacer referencia a un CTE dos veces?

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 

Obviamente, mi consulta anterior es desigual, pero es solo para ilustrar mi punto. Quiero una página de resultados Y el número total de coincidencias. ¿Cómo hago esto sin tener que copiar y pegar literalmente las 20 líneas completas de CTE?

+3

Tal vez considero cambiar el nombre de esta pregunta ya que la respuesta aceptada en realidad no utiliza el CTE dos veces. –

Respuesta

15

Puede usar comas para crear múltiples CTE que hagan referencia a los CTE anteriores.

Sólo para ilustrar lo que quiero decir:

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

Ésta no es la una buena solución.

La mejor solución que encontré para tener el recuento total en un CTE sin contar los registros se describe en this article.

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 
+0

Sí, pensé en esto, pero hay un problema cuando la consulta no devuelve ningún registro. Supongo que podría mezclarlo con UNION ALL y una fila ficticia ... –

+0

Echa un vistazo a la última pieza de código que tomé del artículo. ¿Qué es lo que tiene un recuento de filas ascendentes y descendentes y simplemente agregarlos en los resultados para obtener el número total de filas. Esto funciona muy bien en nuestros entornos de producción. –

+1

¡Ahh brillante! Ese enlace tiene una muy buena manera de lograr esto. –

19

No creo que pueda. De MSDN

Una expresión de tabla común (CTE) puede ser pensamiento de como resultado temporal establecido que se define dentro del alcance ejecución de un solo SELECT, INSERT, UPDATE, DELETE o CREATE VIEW declaración.

Énfasis en "instrucción única SELECT, INSERT, UPDATE, DELETE o CREATE VIEW".

Esta podría ser una situación en la que desea utilizar un Temporary Table.

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

Si no se conoce la estructura de la mesa antes de la mano se puede utilizar este formulario para crear una tabla temporal:

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

Usted será capaz de utilizar la tabla temporal en la forma usted ha descrito arriba

+1

Además, recomendaría usar esos "SELECT *" solo si realmente los necesita. Pueden causar problemas de rendimiento, y la mayoría de las veces no son realmente necesarios. –

+0

Esta sintaxis para crear la tabla temporal también puede ser útil: Seleccione * En #Records desde ... –

+0

En realidad, tengo una declaración SELECT compleja que debo hacer sobre datos jerárquicos y la forma en que se llama variará mucho dependiendo de la situación. –

4

Se podría agregar un campo que tiene las filas totales en que, por supuesto que va a estar en cada fila

select recs.*,totalrows = (select count(0) from recs) 
from recs 
1

Este es el mejor:

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

Esta es la forma en nos ocupamos de la paginación (sin gestión de sesiones por ahora) en un entorno de producción. Se realiza según lo esperado.

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 
Cuestiones relacionadas