A common table expression (CTE) can be thought of as a temporary result set
CTE are easier to read Nested queries are hard to inspect, you have to undertand all the nested queries first, then go up to the main query, while in the CTE approach, the read process is more natural, from top to bottom.
In Sql, CTE is represented as a with
clause.
To add a CTE to your query simply use the With
method.
//:playground
var activePosts = new Query("Comments")
.Select("PostId")
.SelectRaw("count(1) as Count")
.GroupBy("PostId")
.HavingRaw("count(1) > 100");
var query = new Query("Posts")
.With("ActivePosts", activePosts) // now you can consider ActivePosts as a regular table in the database
.Join("ActivePosts", "ActivePosts.PostId", "Posts.Id")
.Select("Posts.*", "ActivePosts.Count")
WITH [ActivePosts] AS (
SELECT [PostId], count(1) as Count FROM [Comments] GROUP BY [PostId] HAVING count(1) > 100
)
SELECT [Posts].*, [ActivePosts].[Count] FROM [Posts] INNER JOIN [ActivePosts] ON [ActivePosts].[PostId] = [Posts].[Id]
You can use the WithRaw
method if you want to pass a raw Sql Expression.
//:playground
var query = new Query("Posts")
.WithRaw("ActivePosts", "select PostId, count(1) as count from Comments having count(1) > ?", new [] {50}) // now you can consider ActivePosts as a regular table in the database
.Join("ActivePosts", "ActivePosts.PostId", "Posts.Id")
.Select("Posts.*", "ActivePosts.Count")
WITH [ActivePosts] AS (
select PostId, count(1) as count from Comments having count(1) > 50
)
SELECT [Posts].*, [ActivePosts].[Count] FROM [Posts] INNER JOIN [ActivePosts] ON [ActivePosts].[PostId] = [Posts].[Id]
As in the example above, you can pass an IEnumerable<object>
to pass custom binding.