views:

2734

answers:

6

From this post How to use ROW_NUMBER in the following procedure?

There are two versions of answers where one uses a SubQuery and the other uses a CTE to solve the same problem.

Now then, what is the advantage of using a CTE (Common Table Expression) over a sub-query(thus, more readable what the query is actually doing)

The only advantage of using a CTE over sub select is that I can actually name the sub query. Are there any other differences between those two when a CTE is used as a simple (non-recursive) CTE?

+5  A: 

In the sub-query vs simple (non-recursive) CTE versions, they are probably very similar. You would have to use the profiler and actual execution plan to spot any differences, and that would be specific to your setup (so we can't tell you the answer in full).

In general; A CTE can be used recursively; a sub-query cannot. This makes them especially well suited to tree structures.

Marc Gravell
Sorry, I should have been more clearer in the my question. What would be the difference between CTE and Subquery in the context where CTE is used LIKE subquery?
Sung Meister
Clarified in response
Marc Gravell
@Marc Gravell: We can do more than that though, as the behavior of the profiler is not guaranteed, vs the behavior of the CTE, which is (in terms of evaluation).
casperOne
+1  A: 

Unless I'm missing something, you can name CTE's and subqueries just as easily.

I guess the main difference is readability (I find the CTE more readable because it defines your subquery up front rather than in the middle).

And if you need to do anything with recursion, you are going to have a bit of trouble doing that with a subquery ;)

AlexCuse
The main difference is most certainly not readability.
Evan Carroll
I'm not sure there is *any* non-aesthetic difference (though I expect that in certain situations there may be slight differences in execution plan). Care to enlighten me?
AlexCuse
+10  A: 

The main advantage of the Common Table Expression is twofold. The first is that the result set will be evaluated once and then multiple uses of that resultset in queries that follow will not cause the entire CTE to be reevaluated.

Think of a CTE as a temp table variable that you insert the rows into before the query that uses it (and only the query that uses it).

With a sub-query, if you need to use the results more than once, you have to duplicate the query, but SQL Server might evaluate that twice as well (the optimizer might optimize it out, but that's an implementation detail).

CTEs also have the benefit of being able to be called recursively, but that's not really the important point in the context of this question.

casperOne
+1 that is something I didn't know about.
Sung Meister
"Think of a CTE as a temp table variable" does that mean CTE is stored in disk or in memory?
Sung Meister
You cannot use the CTE or subquery in multiple queries, by definition. I'm pretty sure that the optimizer handles the subquery the same way it would handle the CTE (evaluating the result set only once, regardless of how many times it is used within the 1 query)
AlexCuse
@AlexCuse: I think I've clarified the context of the CTE enough, but I added more to try and clarify more.
casperOne
@AlexCuse: There is also no implication that the CTE or subquery can be used in multiple places. The difference between the CTE and optimizer though is that the behavior of the CTE is guaranteed, whereas the behavior of the optimizer is not.
casperOne
and I will concede that there could be some edge cases where the optimizer chokes and the subquery is evaluated more than once, I have not run into any though. Then again, I use CTE's wherever I can ;)
AlexCuse
@AlexCuse: By multiple places, I mean outside of the query that the subquery or the CTE is attached to. In other words, the CTE is only applicable for ONE query.
casperOne
Ok, I'm on board now. Thanks for editing the response. I'll delete all my silly comments now ;)
AlexCuse
This answer is very misleading. A CTE is not a temp table; think of a CTE as a view that is defined only for your current query. Just like a view, a CTE is expanded and folded into the overall query plan. Global optimization will still occur, but do not think that just because you use a CTE you will only execute the query once. Here is a trivial example that fits in this space: WITH vw AS ( SELECT COUNT(*) c FROM Person )SELECT a.c, b.cFROM vw a, vw b; The query plan will clearly show two scans/aggregations and a join instead of just projecting the same result twice.
Michael Petito
+1  A: 

CTE's are most useful for recursion:

WITH hier(cnt) AS (
        SELECT  1
        UNION ALL
        SELECT  cnt + 1
        FROM    hier
        WHERE   cnt < @n
        )
SELECT  cnt
FROM    hier

will return @n rows (up to 100). Useful for calendars, dummy rowsets etc.

They are also more readable (in my opinion).

Apart from this, CTE's and subqueries are identical.

Quassnoi
+1  A: 

One important difference (not an advantage) is that a CTE is only going to work with SQL Server. If you ever need to move to a different database, it will be a lot more work to refactor the CTE than an equivalent sub query.

On the other hand, once you come to terms with the syntax CTE's are really nice, even if you don't use them recursively, and the odds of moving to a whole new database without having to do a pretty serious re-write are pretty small anyway.

Joel Coehoorn
+1 Good point; Ok, I have never thought about porting code between different RDBMS...
Sung Meister
Actually - I disagree. The CTE construct is a SQL standard, and has been implemented by Oracle, IBM in DB2, Firebird, PostgreSQL - it's *NOT* a Microsoft-specific extension!
marc_s
-1 totally inaccurate.
Evan Carroll
The `WITH` syntax is now ANSI standard, including recursive WITH clauses.
OMG Ponies
+1  A: 

Adding to others' answers, if you have one and the same subquery used several times, you can replace all these subqueries with one CTE. This allows you to reuse your code better.

AlexKuznetsov