2009-10-19 3 views
17

Meine gespeicherte Prozedur wie folgt aussieht:Warum kann ich nicht auf mein CTE zugreifen, nachdem ich es einmal verwendet habe?

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

UPDATE ... (using my CTE) 



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

Kann ich es nur einmal benutzen?

+0

Dies ist ein gutes Beispiel dafür, warum wir alle Semikola in unserem T-SQL verwenden sollten. Wenn Sie ';' nach den UPDATE- und DELETE-Anweisungen richtig platzieren, wird klar, dass der CTE Teil der UPDATE-Anweisung ist. – NReilingh

Antwort

19

In Ihrem Beispielcode bleibt das CTE nur für das UPDATE bestehen. Wenn Sie es länger brauchen, sollten Sie eine #tempTable oder @tableVariable damit füllen und dann UPDATE und DELETE von diesen.

Sie können auch Ihr UPDATE erweitern, um eine OUTPUT-Klausel wie die folgende zu verwenden, damit Sie die betroffenen Zeilen erfassen können. Und sie in der DELETE verwenden, wie hier:

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

Große Antwort. Ich verwende SQL Server seit Jahren und wusste nicht, dass Sie OUTPUT ausführen können. Das wird in Zukunft sicher nützlich sein. – WesleyJohnson

3

Ein CTE-Ausdruck ist nur in seinem Körper gültig. Wenn Sie es an anderen Orten verwenden möchten, sollten Sie auch die WITH-Klausel wiederholen.

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

aber es funktioniert in der UPDATE, nur nicht in der DELETE, macht das Sinn? – mrblah

+0

Natürlich. "UPDATE" ist der Körper Ihres CTE. –

+0

ist nicht der Körper innerhalb der() nach dem AS-Schlüsselwort. Update und DELETE sind außerhalb der(). – mrblah

3

Yep, die WITH MYCTE Klausel danach in mehreren Abfragen ist kein permanentes Objekt erstellen zu verwenden: es die eine Abfrage nur ist Modifizieren Sie diese Klausel, um das Hinzufügen sind! Wenn Sie sehr unterschiedliche Funktionen benötigen, sollten Sie stattdessen Ansichten verwenden ...

+1

... oder temporäre Tabellen (# oder @). –

4

CTE schafft nicht alles 'echtes'. Sie sind lediglich ein Sprache Element, eine Möglichkeit, einen Tabellenausdruck auszudrücken, der wiederholt in einer Anweisung verwendet wird. Wenn Sie sagen,

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

sagen

nur ein weiterer Weg ist
select ... from (select ... from table where ....) as cteFoo where ... 

CTE und abgeleitete Tabellen sind sehr ähnlich, jede Abfrage abgeleitete Tabellen verwendet als CTE rewriten werden kann, und jede nicht-rekursive CTE kann unter Verwendung von abgeleiteten Tabellen als Abfrage umgeschrieben werden. Persönlich bevorzuge ich das CTE-Formular, da es prägnanter und leichter zu lesen ist.

CTEs ermöglichen ein Tabellenausdruck mehrfach verwendet nur einmal erklären:

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

dies vergleichen mit der semantisch ähnlicher Form abgeleitete Tabelle:

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

Der CTE deutlich besser lesbar ist. Aber Sie müssen verstehen, dass die beiden Formulare die gleiche Abfrage erzeugen. Das CTE-Formular könnte vorschlagen, dass ein Zwischenergebnis erstellt wird, dann wird der Join auf dem Zwischenergebnis ausgeführt, aber das ist nicht wahr. Das CTE-Formular wird genau in die gleiche Form wie die abgeleitete Tabelle 1 kompiliert, was deutlich macht, dass die Tabellenausdruck der CTE zweimal ausgeführt wird.