2009-10-19 17 views
17

thủ tục lưu trữ của tôi trông giống như:tại sao tôi không thể truy cập CTE của mình sau khi đã sử dụng nó một lần?

WITH MYCTE(....) 
AS 
(
... 
) 

UPDATE ... (using my CTE) 



DELETE (using my CTE) <--- says the object, my CTE, doesn't exist 

Tôi có thể chỉ sử dụng nó một lần?

+0

Đây là một ví dụ tốt về lý do tại sao tất cả chúng ta nên sử dụng dấu chấm phẩy trong T-SQL của chúng tôi. Có ';' được đặt đúng sau câu lệnh UPDATE và DELETE làm cho rõ ràng rằng CTE là _part of_ câu lệnh UPDATE. – NReilingh

Trả lời

19

Trong mã ví dụ của bạn, CTE chỉ tồn tại cho CẬP NHẬT. Nếu bạn cần nó kéo dài hơn, hãy xem xét điền #tempTable hoặc @tableVariable với nó, sau đó UPDATE và DELETE từ chúng.

Bạn cũng có thể tăng cường CẬP NHẬT để sử dụng mệnh đề OUTPUT, như sau, để bạn có thể chụp các hàng bị ảnh hưởng. Và sử dụng chúng trong DELETE, như ở đây:

set nocount on 
DECLARE @Table  table (PK int, col1 varchar(5)) 
DECLARE @SavedPks table (PK int) 

INSERT INTO @Table VALUES (1,'g') 
INSERT INTO @Table VALUES (2,'g') 
INSERT INTO @Table VALUES (3,'g') 
INSERT INTO @Table VALUES (4,'g') 
INSERT INTO @Table VALUES (5,'x') 
INSERT INTO @Table VALUES (6,'x') 
set nocount off 

;WITH MYCTE 
AS 
(
    SELECT PK, col1 FROM @Table 
) 
UPDATE MYCTE 
    SET col1='xyz' 
    OUTPUT INSERTED.PK 
     INTO @SavedPks 
    WHERE col1='g' 

SELECT 'A',* FROM @Table 

DELETE @Table 
    WHERE PK IN (SELECT PK from @SavedPks) 

SELECT 'B',* FROM @Table 

OUTPUT:

(4 row(s) affected) 
    PK   col1 
---- ----------- ----- 
A 1   xyz 
A 2   xyz 
A 3   xyz 
A 4   xyz 
A 5   x 
A 6   x 

(6 row(s) affected) 

(4 row(s) affected) 

    PK   col1 
---- ----------- ----- 
B 5   x 
B 6   x 

(2 row(s) affected) 
+1

Câu trả lời hay. Tôi đã sử dụng SQL Server trong nhiều năm và không biết bạn có thể làm OUTPUT. Điều đó chắc chắn sẽ có ích trong tương lai. – WesleyJohnson

3

Biểu thức CTE chỉ hợp lệ trong phần thân của nó. Nếu bạn muốn sử dụng nó ở những nơi khác, bạn cũng nên lặp lại mệnh đề WITH.

WITH MYCTE(....) AS (...) 
UPDATE ... (using my CTE); 
-- a semicolon is necessary for statements followed by a CTE declaration 

WITH MYCTE(....) AS (...) 
DELETE (using my CTE); 
+0

nhưng nó đang làm việc trong CẬP NHẬT, chỉ cần không có trong DELETE, điều đó có ý nghĩa không? – mrblah

+0

Tất nhiên. 'UPDATE' là phần thân của CTE của bạn. –

+0

Không phải là nội dung bên trong() sau từ khóa AS. Cập nhật và DELETE nằm ngoài(). – mrblah

3

Yep, mệnh đề WITH MYCTE không tạo ra một đối tượng thường xuyên sử dụng trong nhiều thắc mắc sau: nó chỉ sửa đổi một truy vấn mà bạn đang thêm khoản đó để! Nếu bạn cần functonality rất khác nhau, hãy xem xét, thay vào đó, bằng cách sử dụng quan điểm ...

+1

... hoặc bảng tạm thời (# hoặc @). –

4

CTE không tạo ra bất cứ điều gì 'thực tế'. Chúng chỉ đơn thuần là một phần tử , một cách để biểu diễn một biểu thức bảng sẽ được sử dụng, có thể nhiều lần, trong một câu lệnh. Khi bạn nói

WITH cteFoo AS (select ... from table where ...) 
select ... from cteFoo where ... 

chỉ là một cách khác để nói

select ... from (select ... from table where ....) as cteFoo where ... 

CTE và bảng có nguồn gốc rất giống nhau, bất kỳ truy vấn sử dụng bảng có nguồn gốc có thể được rewriten như một CTE, và bất kỳ CTE không đệ quy có thể được viết lại dưới dạng truy vấn bằng cách sử dụng các bảng có nguồn gốc. Cá nhân, tôi nhiều hơn preffer các hình thức CTE là ngắn gọn hơn và dễ đọc.

CTEs cho phép một biểu bảng được sử dụng nhiều lần để được tuyên bố chỉ một lần:

WITH cte AS (select ... from table where ...) 
    select ... 
    from cte a join cte b on ... 
    where ... 

Hãy so sánh điều này với các hình thức bảng có nguồn gốc ngữ nghĩa tương tự:

select ... 
from (
    select ... from table where ...) as a 
join (
    select ... from table where ...) as b 
    on ... 
where ... 

Các CTE rõ ràng là dễ đọc hơn. Nhưng bạn phải hiểu rằng hai biểu mẫu này đang tạo ra cùng một truy vấn. Dạng CTE có thể gợi ý rằng một kết quả trung gian được tạo ra sau đó kết nối được chạy trên kết quả trung gian, nhưng điều này không đúng. Các hình thức CTE được biên dịch thành chính xác cùng một hình thức như một bảng dẫn xuất, mà làm cho rõ ràng thực tế là bảng exe của CTE được chạy hai lần.

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