views:

726

answers:

3

I need to do something like this but SQL Server 2008 doesn't like it. My query is actually more complex than this and I realize this isn't the best way to accomplish what I'm doing but my focus is on the functionality of the WITH statement and not the select and where statements.

WITH stuff1 AS ( select name, startdate, id from employees where startdate > 0 )

WITH stuff2 AS ( select name, startdate, id from stuff1 )

select * from stuff2 where id > 10

A: 

Nope, you can only have one CTE in a statement as I found out the other day.

EDIT: And that WITH statement is a Common Table Expression, very handy feature.

Kezzer
Actually, you can have multiple CTEs, and they can build on each other and even multiple CTEs within the CTE chain, separate with a comma - only one WITH statement can be used.
Cade Roux
I hadn't realised they had to be comma-separated. This will be handy. I've been reading my SQL 2008 book and they mention CTE's, but they don't mention the use of multiple CTE's in one query, which is a shame.
Kezzer
Yep, I posted an example below. I've been using it very heavily for the last year in a port from a 3GL system.
Cade Roux
A: 

You may be able to us a series of sub-queries. Or sub-queries nested in a CTE.

An example of sub-queries using Northwind:

SELECT * FROM 
    (SELECT * FROM
        (SELECT * FROM dbo.Employees WHERE Country = 'USA') as TableFiltered1
     ) AS TableFilterd2 WHERE City = 'Seattle'

You can use two CTEs, but maybe not the way you wanted to, see:
http://www.4guysfromrolla.com/webtech/071906-1.shtml

tyndall
In my experience, anything with subqueries can be transformed very quickly to use CTEs. The reduced nesting level and ability to layer them very easily in declaration style and not repeating yourself makes a significant difference to readability and maintainability.
Cade Roux
I agree. That's kind of why I included the link that showed an example of comma-separated CTE. I think its the 3rd or 4th example in the '4guys' link. I was trying to layout all the options.
tyndall
+8  A: 

I do it all the time:

WITH stuff1 AS (
    SELECT name
           ,startdate
           ,id
    FROM employees
    WHERE startdate > 0
)
,stuff2 AS (
    SELECT name
           ,startdate
           ,id
    FROM stuff1
)
SELECT *
FROM stuff2
WHERE id > 10

As far as I can tell, I haven't reached a limit in CTEs.

The only thing you can't do (which would be pretty useful) is reuse CTEs in separate SELECTs:

WITH stuff1 AS (
    SELECT name
           ,startdate
           ,id
    FROM employees
    WHERE startdate > 0
)
,stuff2 AS (
    SELECT name
           ,startdate
           ,id
    FROM stuff1
)
SELECT *
FROM stuff2
WHERE id > 10
;
SELECT *
FROM stuff2
WHERE id < 10

Say. Instead you have to copy and paste the entire CTE chain again.

Cade Roux
does the above work without the ; terminator between the first and second selects?
Russ Cam
No. CTEs can only be used on a single operation. INSERT/SELECT/DELETE whatever, but they are basically consumed at that point.
Cade Roux
good to know, thanks!
Russ Cam
That's awesome! This is what I was looking for.
Paul Mendoza
Thanks very much for this, very handy indeed and I definitely need it for some of my stored procedures. Thanks again!
Kezzer