2011-09-05 39 views
6

Câu hỏi này đã được hỏi vài lần khác, nhưng tôi vẫn không quản lý để sắp xếp ra câu trả lời đúng hoặc đúng cách để làm điều này:Làm thế nào để tổ CTE đúng

...

;WITH CTE AS 
(
    SELECT * FROM ... 
) 
SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss' 
FROM CTE 
WHERE (Loss >= @MinRetention) 

này không hoạt động và tôi không thể tạo thủ tục lưu sẵn, rõ ràng là tôi không thể sử dụng Loss trong WHERE vì không tồn tại trong phạm vi đó.

Tôi muốn sử dụng một CTE để quấn một này vì vậy tôi có thể đặt WHERE trên một bên ngoài nhưng không dường như không làm việc, cố gắng này:

;WITH CTE AS 
(
    SELECT * FROM ... 
) 
SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss' 
FROM CTE, 
RESULTS AS 
(SELECT * FROM CTE) 
    SELECT * 
    FROM RESULTS 
    WHERE (Loss >= @MinRetention) 

Nhưng nó không biên dịch trong SQL Máy chủ, tôi nhận được một lỗi rằng một '(' là sai chỗ nhiều hàng ở trên nhưng không có gì để làm, nếu tôi loại bỏ CTE thứ hai nó hoạt động tốt.

Tôi chỉ muốn tránh trùng lặp mã, không muốn gọi cho tôi [ udf_BetaInv] hai lần trong lựa chọn và cũng ở nơi.

+0

Bạn có nghĩa là '[Mất]' (tên cột) không phải 'Mất' '(một chuỗi) không? Không chắc chắn nếu điều đó gây ra lỗi, mặc dù – Rup

Trả lời

13

Bạn có một số trung gian SELECT mà bạn không nên có. Điều này sẽ hoạt động:

;WITH CTE AS 
(
    SELECT * FROM ... 
), 
RESULTS AS 
(
    SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss' 
    FROM CTE 
) 
SELECT * 
FROM RESULTS 
WHERE (Loss >= @MinRetention) 
+0

Cảm ơn, công việc tuyệt vời là tốt, không nhận ra tôi đã có quá nhiều lựa chọn: D –

+1

Nó không cần thiết nhưng một pratice tốt để rõ ràng tên cột trong tên CTE của bạn, tức là .... KẾT QUẢ ([tên cột từ CTE], mất mát) .... Bạn sẽ cảm ơn bản thân sau: P. – deutschZuid

7

Rõ ràng là probl với truy vấn đầu tiên là 'Mất' chỉ là một bí danh cột và không thể được sử dụng trong mệnh đề WHERE. Bạn nói đúng rằng việc sử dụng nó trong một CTE sẽ tránh sao chép biểu thức. Đây là cách bạn làm điều đó;

WITH CTE AS 
( 
    SELECT * FROM ... 
), 
CteWithLoss AS ( 
    SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss' 
    FROM CTE 
) 
SELECT * 
FROM CteWithLoss 
WHERE (Loss >= @MinRetention); 

Trên một mặt lưu ý: Xem nếu bạn có thể phá vỡ các thói quen bắt đầu từ định nghĩa CTE của bạn với ;WITH và thay vào đó nhận được vào các thói quen kết thúc tất cả các câu lệnh SQL của bạn với một dấu chấm phẩy. Đó là thực hành dễ đọc hơn và tốt hơn.

+0

cảm ơn hoạt động hoàn hảo ngay bây giờ :) –

+0

Tôi cần CTE thứ hai bên trong đầu tiên, truy vấn phụ thuộc vào nó. Có cách nào để làm điều đó? – Akbari

+0

Cộng với một cho "phá vỡ thói quen bắt đầu các định nghĩa CTE của bạn với;" – DaveBoltman

0

Dưới đây là ví dụ về lồng nhau CTE.

with cte_data as 
(
    Select * from [HumanResources].[Department] 
),cte_data1 as 
(
    Select * from cte_data 
) 

select * from cte_data1 
+0

Đó không phải là lồng nhau, chỉ cần một CTE khác tham chiếu một phiên bản trước đó. – DaveBoltman

+0

Đây là Dave lồng nhau. Trong thực tế nó khá nhiều định nghĩa của một CTE lồng nhau. Bạn có nghĩ đến CTE đệ quy không? Đó là một trò chơi bóng hoàn toàn mới và thú vị hơn rất nhiều nhưng không phải là những gì mà OP yêu cầu. –

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