In SQL, a CTE can only be used/referenced in the (one) statement, where it is defined. And we know where statements end by using statement terminators (;
).
SQL Server is forgiving and allows developers not to put these terminators (except for special cases where it does complain) but it's really good practice (and Microsoft recommends it) to use them after every statement. If you had them placed, it would be obvious that your code parses as 3 statements:
--- 1st statement starts ---
with ctegeneric as (select person from people where person = 'dumb')
Select * from ctegeneric ; -- and ends here
--- 2nd statement starts ---
Select * from ctegeneric ; -- and ends here
--- 3rd statement starts ---
Select * from ctegeneric ; -- and ends here
So your second and third statements should not actually work at all, and will return the error:
INVALID OBJECT NAME: ctegeneric
As soon as the statement where the CTE is made ends, you lose the ability to reference it again.
It's kind of like (this is not valid syntax either, just another way to think about CTEs):
WITH ctegeneric AS (SELECT person
FROM people
WHERE person = 'dumb')
BEGIN
Select * from ctegeneric ;
END
However, you can run the three selects with a UNION/UNION ALL
:
WITH ctegeneric AS (SELECT person
FROM people
WHERE person = 'dumb')
Select * from ctegeneric
UNION
Select * from ctegeneric
UNION
Select * from ctegeneric ;