2012-04-17 106 views
34

我有這個,我在設定的總數上得到一個錯誤。 爲什麼我不能多次訪問cte?多次使用一個CTE

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

不!請不要**改變你的問題!去問另一個。 – RBarryYoung 2012-04-17 18:34:28

+2

我的錯誤,我很抱歉 – gigi 2012-04-17 18:35:10

回答

50

A CTE基本上是一次性視圖。它只會持續一條語句,然後自動消失。

選項包括:

  • 重新定義CTE第二次。這很簡單,只需從WITH...到定義的末尾複製粘貼到SET之前即可。

  • 把你的結果到#temp表或@table可變

  • 結果物化到一個真正的表,並說明

  • 阿爾特略有隻是SELECT COUNT從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

CTE不僅限於單個查詢,而是限於單個語句。您可以有多個查詢使用相同的CTE(如果嵌套,在其他CTE中等)。 – Lucero 2012-04-17 18:29:21

+1

@Lucero我認爲你是挑選「查詢」的定義... – 2012-04-17 18:30:12

+0

@AaronBertrand他有一個點,雖然。我會糾正它。 – JNK 2012-04-17 18:30:55

11

根據定義,CTE僅對一個語句有效。

您可以創建一個inline table-valued function,然後根據需要隨時使用它。內聯函數完成名稱的功能。它的查詢成爲使用它的查詢的一部分(與單獨執行並用作行集的非內聯函數相比)。

+0

作爲一名軟件開發人員,我更喜歡這種方法。它允許我將我的邏輯合併爲一個函數,然後在多個存儲過程中使用它。這對複雜的查詢特別有用。我發現我可以返回一堆列並添加大量連接以使其可重用,但是對於引用它的每個sproc可能不需要,但是sql-server注意不要處理額外連接和列,如果您的sproc沒有使用它們。您也可以讓ITVF(內聯表值函數)調用其他ITVF,以便您可以進一步構建基礎查詢邏輯! – MikeTeeVee 2012-09-11 18:54:01

0

在這種情況下,我用這個:

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

上述答案都是正確的。你可以執行一次CTE,實現你想要的結果。這裏是查詢

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

看來這僅限於只讀操作。試圖更新相同的結果集給我錯誤的基礎上有效的更新聲明與第一個CTE的加入。 – 2017-05-19 19:08:08

+0

我得到這樣的錯誤:「將一個值賦給一個變量的SELECT語句不能與數據檢索操作相結合。」儘管SQL Server 2014。 – user1829319 2017-10-20 05:44:44

+0

它實際上是sql server 2016 – user1829319 2017-10-20 06:07:22