CTE (Common Table Expression) syntax can be a little tricky at first, but once you have a little primer, you will love using them as much as I do. Examine the following code below that uses a derived table from which to select. (Please realize that this is a contrived example and you could of course just join the tables in the query directly.)
USE tempdb GO SELECT t.TableName, c.ColumnName FROM (SELECT OBJECT_ID AS Id, [Name] AS TableName FROM sys.tables) t INNER JOIN (SELECT OBJECT_ID AS Id, [Name] AS ColumnName FROM sys.columns) c ON t.Id = c.Id
The query between the parentheses creates a table structure (that I aliased as “c” and “t” for my two) that only lasts for the life of the query. I can then reference those tables in the query in any way that I would a regular table. However, that syntax can make it very difficult to read, especially in long queries with several complicated derived tables.
Sql Server 2005 introduced a new syntax to be used instead called Common Table Expressions (CTEs). Using a CTE, the above query would be written like this
USE tempdb GO WITH Tbls AS ( SELECT OBJECT_ID AS Id, [Name] AS TableName FROM sys.tables ), Clmns AS ( SELECT OBJECT_ID AS Id, [Name] AS ColumnName FROM sys.columns ) SELECT t.TableName, c.ColumnName FROM Tbls t INNER JOIN Clmns c ON t.Id = c.Id
Alternatively, you can also explictly declare you column names in the CTE definition and not have to alias the columns in the query itself.
USE tempdb GO WITH Tbls (Id, TableName) AS ( SELECT OBJECT_ID, [Name] FROM sys.tables ), Clmns (Id, ColumnName) AS ( SELECT OBJECT_ID, [Name] FROM sys.columns ) SELECT t.TableName, c.ColumnName FROM Tbls t INNER JOIN Clmns c ON t.Id = c.Id
One “gotcha” is that the CTE – beginning with the WITH keyword – must be the first statement that is encountered. All previous statements above it must be terminated with a GO or a semicolon. If you ran the following
USE tempdb GO SELECT 'Here Comes the Error' WITH Tbls (Id, TableName) AS ( SELECT OBJECT_ID, [Name] FROM sys.tables ), Clmns (Id, ColumnName) AS ( SELECT OBJECT_ID, [Name] FROM sys.columns ) SELECT t.TableName, c.ColumnName FROM Tbls t INNER JOIN Clmns c ON t.Id = c.Id
You’d get the errors shown below (or something very close)
Msg 102, Level 15, State 1, Line 4 Incorrect syntax near 'Tbls'. Msg 102, Level 15, State 1, Line 8 Incorrect syntax near ','.
Some people even just make a habit of actually prefixing the WITH with a semicolon every time to make sure that everything goes off without a hitch. If I do run this script instead there are no issues.
USE tempdb GO SELECT 'No Problems Here' ;WITH Tbls (Id, TableName) AS ( SELECT OBJECT_ID, [Name] FROM sys.tables ), Clmns (Id, ColumnName) AS ( SELECT OBJECT_ID, [Name] FROM sys.columns ) SELECT t.TableName, c.ColumnName FROM Tbls t INNER JOIN Clmns c ON t.Id = c.Id
This is just a quick primer on CTEs, but I hope that you can find it useful. I really find that it cleans my code up quite a bit.