2009-10-19 15 views
17

mia stored procedure assomiglia:perché non riesco ad accedere al mio CTE dopo che l'ho usato una volta?

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

UPDATE ... (using my CTE) 



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

Posso usare solo una volta?

+0

Questo è un buon esempio del motivo per cui dovremmo utilizzare il punto e virgola nel nostro T-SQL. Avendo ';' posizionato correttamente dopo le istruzioni UPDATE e DELETE chiarisce che il CTE è _part of_ l'istruzione UPDATE. – NReilingh

risposta

19

Nel codice di esempio, il CTE persiste solo per l'AGGIORNAMENTO. Se ne hai bisogno per durare più a lungo, considera di popolarlo con #tempTable o @tableVariable, quindi UPDATE e DELETE da quelli.

È inoltre possibile aumentare l'UPDATE per utilizzare una clausolacome la seguente, in modo da poter acquisire le righe interessate. E usarli nel DELETE, come qui:

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 

USCITA:

(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

Ottima risposta. Utilizzo SQL Server da anni e non sapevo che potessi fare OUTPUT. Questo sarà sicuramente utile in futuro. – WesleyJohnson

3

Un'espressione CTE è valida solo nel suo corpo. Se si desidera utilizzarlo in altri luoghi, è necessario ripetere anche la clausola 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

ma funziona in UPDATE, non solo nel DELETE, ha senso? – mrblah

+0

Ovviamente. 'UPDATE' è il corpo del tuo CTE. –

+0

Non è il corpo all'interno di() dopo la parola chiave AS. Update e DELETE sono al di fuori di(). – mrblah

3

Sì, la clausola WITH MYCTE non sta creando un oggetto fisso da utilizzare in più query dopo: è solo modificando la sola query si sta aggiungendo che clausola! Se hai bisogno di una functonalità molto diversa, considera, invece, l'utilizzo di viste ...

+1

... o tabelle temporanee (# o @). –

4

CTE non crea nulla 'reale'. Sono semplicemente un elemento lingua , un modo per esprimere un'espressione di tabella che verrà utilizzata, possibile più volte, in una dichiarazione. Quando si dice

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

è solo un altro modo di dire

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

CTE e tabelle derivate sono molto simili, qualsiasi query utilizzando le tabelle derivate può essere rewriten come CTE, e ogni non-ricorsiva CTE può essere riscritto come una query utilizzando le tabelle derivate. Personalmente, preferisco molto di più il modulo CTE in quanto è più conciso e facile da leggere.

CTE consentono un'espressione di tabella usata più volte per essere dichiarare soltanto una volta:

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

confronta questo con l'semanticamente simile forma di tabella derivata:

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

Il CTE è chiaramente più leggibile. Ma devi capire che le due forme stanno producendo la stessa query. Il modulo CTE potrebbe suggerire che viene creato un risultato intermedio, quindi il join viene eseguito sul risultato intermedio, ma questo non è vero. Il modulo CTE è compilato esattamente nella stessa forma di quello derivato della tabella, il che rende chiaro il fatto che l'espressione della tabella della CTE viene eseguita due volte.

Problemi correlati