2012-04-17 14 views
34

Tengo esto, y me sale un error en el conjunto total. ¿Por qué no puedo acceder a un cte muchas veces?Use un CTE muchas veces

ALTER PROCEDURE [dbo].[GetLeaguePlayers] 
(
    @idleague int, 
    @pageNumber int, 
    @pageSize int, 
    @total int OUTPUT 
) 
AS 
WITH CTEPlayers AS 
(
    SELECT ROW_NUMBER() OVER (ORDER BY p.Name) AS RowNumber, p.Id, p.Name, t.Name AS Team 
    FROM Players p INNER JOIN Teams t ON p.IdTeam=t.Id INNER JOIN Leagues l ON l.Id=t.IdLeague 
    WHERE [email protected] 
) 
SELECT Id, Name 
FROM CTEPlayers c 
WHERE RowNumber>@pageSize*(@pageNumber-1) AND RowNumber<@pageSize*@pageNumber; 
SET @total = (SELECT COUNT(*) FROM CTEPlayers) 
+11

NO! ¡No *** cambie su pregunta! Ve a preguntar a otro en su lugar. – RBarryYoung

+2

mi error, lo siento – gigi

Respuesta

50

A CTE es básicamente una vista desechable. Solo persiste en una sola declaración y luego desaparece automáticamente.

Sus opciones incluyen:

  • redefinir el CTE una segunda vez. Esto es tan simple como copiar y pegar desde WITH... hasta el final de la definición anterior a su SET.

  • Ponga sus resultados en una tabla #temp o una @table variables

  • materializan los resultados en una tabla real y de referencia que

  • Alter poco a poco SELECT COUNT de su CTE:

.

SELECT @total = COUNT(*) 
FROM Players p 
INNER JOIN Teams t 
    ON p.IdTeam=t.Id 
INNER JOIN Leagues l 
    ON l.Id=t.IdLeague 
WHERE [email protected] 
+7

Los CTE no están restringidos a una sola consulta, sino a una sola declaración. Puede hacer que múltiples consultas utilicen el mismo CTE (si están anidados, en otros CTE, etc.). – Lucero

+1

@Lucero Creo que estás eligiendo la definición de "consulta" ... –

+0

@AaronBertrand, aunque tiene un punto. Lo corregiré. – JNK

11

Un CTE es, por definición, solo válido para una declaración.

Puede crear un inline table-valued function y luego usarlo tantas veces como desee. La función en línea hace lo que su nombre sugiere; su consulta se convierte en parte de la consulta que la usa (a diferencia de las funciones no en línea que se ejecutan por separado y se usan como un conjunto de filas).

+0

Como desarrollador de software, prefiero este enfoque. Me permite consolidar mi lógica en una función y luego usarla en múltiples procedimientos almacenados. Es especialmente útil para consultas complejas. Descubrí que puedo devolver un montón de columnas y agregar muchas combinaciones para que sea reutilizable, sin embargo, puede que no sea necesario para cada sproc que lo haga referencia, pero sql-server se cuida de no procesar las uniones y columnas adicionales si su sproc no los está usando. También puede hacer que las funciones de ITVF (Inline Table-Valued Functions) llamen a otras ITVF para que pueda construir sobre la base de su lógica de consulta aún más. – MikeTeeVee

0

En este caso, yo uso esto:

ALTER PROCEDURE [dbo].[GetLeaguePlayers] 
(
@idleague int, 
@pageNumber int, 
@pageSize int, 
@total int OUTPUT 
) 
AS 

WITH CTEPlayers AS 
(
    SELECT ROW_NUMBER() OVER (ORDER BY p.Name) AS RowNumber,  
     COUNT(1) OVER() AS RecordCount, 
    p.Id, p.Name, 
    t.Name AS Team 
    FROM Players p 
     INNER JOIN Teams t ON p.IdTeam=t.Id 
     INNER JOIN Leagues l ON l.Id=t.IdLeague 
    WHERE [email protected] 
) 

SELECT RowNumber, 
    CAST(CEILING(CAST(RecordCount AS FLOAT)/CAST(@pageSize AS FLOAT)) AS INT) PageCount, 
    RecordCount, 
    Id, 
    Name 
FROM CTEPlayers c 
WHERE RowNumber > @pageSize*(@pageNumber-1) AND RowNumber < @pageSize*@pageNumber; 
8

Ninguna de las respuestas anteriores son correctas ... Puede ejecutar una vez CTE y lograr el resultado deseado .. Ésta es la consulta

ALTER PROCEDURE [dbo].[GetLeaguePlayers] 
(
    @idleague int, 
    @pageNumber int, 
    @pageSize int, 
    @total int OUTPUT 
) 
AS 
WITH CTEPlayers AS 
(
    SELECT p.Id, p.Name, t.Name AS Team 
    FROM Players p INNER JOIN Teams t ON p.IdTeam=t.Id INNER JOIN Leagues l ON l.Id=t.IdLeague 
    WHERE [email protected] 
), 
TotalCount AS 
(
SELECT COUNT(*) AS Total FROM CTEPlayers 
), 
Final_Result AS 
(
SELECT ROW_NUMBER() OVER (ORDER BY p.Name) AS RowNumber, p.Id, p.Name, t.Name AS Team, 
    (SELECT Total FROM TotalCount) AS Total 
    FROM CTEPlayers 
) 
SELECT Id, Name, @total = Total 
FROM Final_Results c 
WHERE RowNumber>@pageSize*(@pageNumber-1) AND RowNumber<@pageSize*@pageNumber; 
+0

Parece que esto está restringido a las operaciones de solo lectura. Intentar actualizar el mismo conjunto de resultados me está dando errores en una declaración de actualización válida basada en una combinación con el primer CTE. –

+0

Me sale este error al hacerlo: "Una sentencia SELECT que asigna un valor a una variable no debe combinarse con operaciones de recuperación de datos". SQL Server 2014 sin embargo. – user1829319

+0

Su servidor en realidad sql 2016 – user1829319

Cuestiones relacionadas