2012-04-17 27 views
34

Tôi có điều này và tôi gặp lỗi tại tổng số đã đặt. Tại sao tôi không thể truy cập một cte nhiều lần?Sử dụng một CTE nhiều lần

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

KHÔNG! Đừng *** KHÔNG ** thay đổi câu hỏi của bạn! Thay vào đó, hãy hỏi một người khác. – RBarryYoung

+2

lỗi của tôi, tôi xin lỗi – gigi

Trả lời

50

A CTE về cơ bản là chế độ xem dùng một lần. Nó chỉ tồn tại cho một tuyên bố duy nhất, và sau đó tự động biến mất.

tùy chọn của bạn bao gồm:

  • Xác định lại các CTE một lần thứ hai. Điều này đơn giản như sao chép-dán từ WITH... đến cuối của định nghĩa trước SET của bạn.

  • Đặt kết quả của bạn vào một bảng #temp hoặc một @table biến

  • Materialise kết quả vào một bảng động sản và tài liệu tham khảo mà

  • Alter nhẹ chỉ SELECT COUNT từ CTE của bạn:

.

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 không bị giới hạn đối với một truy vấn duy nhất, mà là một câu lệnh duy nhất. Bạn có thể có nhiều truy vấn sử dụng cùng một CTE (nếu lồng nhau, trong các CTE khác, v.v.). – Lucero

+1

@Lucero Tôi nghĩ bạn đang chọn nitro định nghĩa về "truy vấn" ... –

+0

@AaronBertrand anh ta có một điểm. Tôi sẽ sửa nó. – JNK

11

CTE, theo định nghĩa, chỉ hợp lệ cho một câu lệnh.

Bạn có thể tạo inline table-valued function và sau đó sử dụng tùy chọn này bao nhiêu lần tùy thích. Hàm nội tuyến thực hiện những gì tên gợi ý; truy vấn của nó trở thành một phần của truy vấn bằng cách sử dụng nó (trái ngược với các hàm không nội tuyến được thực hiện riêng biệt và được sử dụng như một rowset).

+0

Là một nhà phát triển phần mềm, tôi thích cách tiếp cận này. Nó cho phép tôi hợp nhất logic của mình thành một hàm và sau đó sử dụng nó trên nhiều thủ tục được lưu trữ. Nó đặc biệt hữu ích cho các truy vấn phức tạp. Tôi đã tìm thấy rằng tôi có thể trả về một loạt các cột và thêm rất nhiều kết nối để làm cho nó có thể tái sử dụng được, tuy nhiên có thể không cần thiết cho mọi sproc tham chiếu nó, nhưng máy chủ sql sẽ cẩn thận không xử lý các phép nối và cột phụ nếu sproc không sử dụng chúng. Bạn cũng có thể có ITVF (các hàm có giá trị nội tuyến) gọi cho người khác ITVF để bạn có thể xây dựng dựa trên logic truy vấn cơ bản của bạn hơn nữa! – MikeTeeVee

0

Trong trường hợp này, tôi sử dụng này:

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

Không ai trong số các câu trả lời trên đều đúng ... Bạn có thể thực hiện CTE một lần và đạt được kết quả bạn muốn .. đây là truy vấn

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

Dường như điều này bị hạn chế đối với các thao tác chỉ đọc. Cố gắng cập nhật cùng một tập kết quả sẽ cho tôi lỗi trên một câu lệnh cập nhật hợp lệ dựa trên sự tham gia với CTE đầu tiên. –

+0

Tôi nhận được lỗi này làm như vậy: "Một câu lệnh SELECT gán giá trị cho một biến không được kết hợp với các hoạt động truy xuất dữ liệu." Mặc dù vậy, SQL Server 2014. – user1829319

+0

Máy chủ sql thực sự của nó 2016 – user1829319

Các vấn đề liên quan