Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why can't I access my CTE after I used it once?

Tags:

My stored procedure looks like:

WITH MYCTE(....) AS  ( ... )  UPDATE ... (using my CTE)    DELETE ( using my CTE)  <---  says the object, my CTE, doesn't exist 

Can I only use it once?

like image 946
mrblah Avatar asked Oct 19 '09 20:10

mrblah


People also ask

Can a CTE only be used once?

Now, you can now see that the execution plan only scans the Posts and Users tables once each, instead of once for every UNION ALL set. The CTE runs only once.

Can I use CTE more than once?

Unlike a derived table, a CTE behaves more like an in-line view and can be referenced multiple times in the same query. Using a CTE makes complex queries easier to read and maintain. Because a CTE can be referred to multiple times in a query, syntax can be simpler.

Are CTE temporary?

A common table expression (CTE) can be thought of as a temporary result set that is defined within the execution scope of a single SELECT, INSERT, UPDATE, DELETE, or CREATE VIEW statement. A CTE is similar to a derived table in that it is not stored as an object and lasts only for the duration of the query.

What is not allowed in CTE?

Cannot use with CTE"SELECT DISTINCT", GROUP BY, PIVOT, HAVING, Scalar aggregation, TOP, LEFT, RIGHT, OUTER JOIN, and Subqueries are not allowed in the CTE query definition of a recursive member. A CTE can be self-referencing and previously defined CTEs in the same WITH clause. Forward referencing is not allowed.


2 Answers

In your example code, the CTE only persists for the UPDATE. If you need it to last longer, consider populating a #tempTable or @tableVariable with it, and then UPDATE and DELETE from those.

You may also augment your UPDATE to use an OUTPUT clause, like the following, so you can capture the affected rows. And use them in the DELETE, like here:

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) 
like image 59
KM. Avatar answered Oct 16 '22 03:10

KM.


Yep, the WITH MYCTE clause is not creating a permanent object to use in multiple queries afterwards: it's only modifying the one query you're adding that clause to! If you need very different functonality, consider, instead, using views...

like image 45
Alex Martelli Avatar answered Oct 16 '22 05:10

Alex Martelli