2012-04-17 16 views
34

Ho questo e ottengo un errore al totale impostato. Perché non riesco ad accedere a una cte molte volte?Utilizzare un CTE più volte

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! Fai *** NON ** cambia la tua domanda! Vai a chiedere un altro invece. – RBarryYoung

+2

errore mio, mi dispiace – gigi

risposta

50

A CTE è sostanzialmente una vista monouso. Persiste solo per una singola istruzione e quindi scompare automaticamente.

Le opzioni includono:

  • ridefinire il CTE una seconda volta. Questo è semplice come copia-incolla da WITH... fino alla fine della definizione prima del tuo SET.

  • Mettere i risultati in una tabella #temp o un @table variabile

  • materializzano i risultati in una tabella reale e di riferimento che

  • Alter leggermente a solo SELECT COUNT dal 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

Le CTE non sono limitate a una singola query, ma a una singola istruzione. È possibile avere più query utilizzare lo stesso CTE (se nidificato, in altri CTE, ecc.). – Lucero

+1

@Lucero Penso che tu stia scegliendo la definizione di "query" ... –

+0

@AaronBertrand ha un punto, però. Lo correggerò. – JNK

11

Una CTE è, per definizione, valida solo per una dichiarazione.

È possibile creare un inline table-valued function e quindi utilizzarlo tutte le volte che lo si desidera. La funzione inline fa ciò che suggerisce il nome; la sua query diventa parte della query che lo utilizza (a differenza delle funzioni non inline che vengono eseguite separatamente e utilizzate come set di righe).

+0

Come sviluppatore di software, preferisco questo approccio. Mi consente di consolidare la mia logica in un'unica funzione e quindi usarla su più stored procedure. È particolarmente utile per query complesse. Ho scoperto che posso restituire un sacco di colonne e aggiungere molti join per renderlo riutilizzabile, tuttavia potrebbe non essere necessario per ogni sproc che lo fa riferimento, ma sql-server si preoccupa di non elaborare i joins e le colonne extra se il tuo sproc non li sta usando. Puoi anche avere le ITVF (funzioni con valori di tabella in linea) per chiamare gli altri ITVF in modo da poter costruire ulteriormente la tua logica di query di base! – MikeTeeVee

0

In questo caso, io uso questo:

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

Nessuna delle risposte sopra sono esatte ... è possibile eseguire CTE una volta e raggiungere il risultato desiderato .. qui è la query

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

Sembra che questo sia limitato alle operazioni di sola lettura. Il tentativo di aggiornare lo stesso set di risultati mi dà errori su una dichiarazione di aggiornamento valida basata su un join con il primo CTE. –

+0

Viene visualizzato questo errore: "Un'istruzione SELECT che assegna un valore a una variabile non deve essere combinata con le operazioni di recupero dati." Tuttavia, SQL Server 2014. – user1829319

+0

È in realtà il server sql 2016 – user1829319