Common Table Expressions (CTE) for SQL Server Developers

Replacement for Sub queries

Sub queries can cause issues as they reduce code readability. In the above example we eliminated sub queries when using CTEs.

There are frequent questions on the forums of how to write a single T-SQL statement with multiple CTEs. I wrote a blog post on this.

Here is how you can use two CTEs to join together. In the following example, sales for 2007 and 2008 are combined.

WITH Prod2007 (ProductNumber,Amount)
AS
(
     SELECT Prod.ProductNumber,SUM(LineTotal)
     FROM Sales.SalesOrderDetail SOD INNER JOIN
     Sales.SalesOrderHeader SOH
     ON SOD.SalesOrderID = SOH.SalesOrderID
     INNER JOIN Production.Product Prod
     ON Prod.ProductID = SOD.ProductID
     WHERE YEAR(OrderDate) = 2007
     GROUP BY Prod.ProductNumber
)
,
Prod2008 (ProductNumber,Amount)
AS
(
     SELECT Prod.ProductNumber,SUM(LineTotal)
     FROM Sales.SalesOrderDetail SOD INNER JOIN
     Sales.SalesOrderHeader SOH
     ON SOD.SalesOrderID = SOH.SalesOrderID
     INNER JOIN Production.Product Prod
     ON Prod.ProductID = SOD.ProductID
     WHERE YEAR(OrderDate) = 2008
     GROUP BY Prod.ProductNumber
)
SELECT Prod2007.ProductNumber,
Prod2007.Amount Sales2007,
Prod2008.Amount Sales2008 ,
Prod2008.Amount - Prod2007.Amount SalesIncrement
FROM Prod2007
INNER JOIN   Prod2008
ON Prod2007.ProductNumber = Prod2008.ProductNumber

Below is the result.

Ranking by Aggregates

If you are using ranking functions for aggregates, you have no other options other than to use sub-queries. However, with CTEs you can use ranking functions easily.

WITH CustomerSum
AS
(
SELECT CustomerID,SUM(TotalDue) AS TotalAmount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
)
SELECT *,RANK() OVER (ORDER BY TotalAmount DESC ) AS OrderRank
FROM CustomerSum

Dynamic Pivot Tables

Pivot tables often neglected as its columns cannot be dynamic. However, with CTEs you can still support dynamic columns with pivot tables.

Below is the traditional Pivot table usage.

-- Pivot
SELECT *
FROM
(SELECT CustomerID, YEAR(OrderDate)AS OrderYear, TotalDue
FROM Sales.SalesOrderHeader) header
PIVOT
(SUM(TotalDue) FOR OrderYear IN ([2006],[2007],[2008])
) AS pvt

This is how you can use this with CTE.

DECLARE @years VARCHAR(1000)
WITH Years
AS
(SELECT Distinct Year(OrderDate) AS Year
FROM Sales.SalesOrderHeader)
SELECT @years = ISNULL(@years+ ',[','[')+ CAST([Year] AS NVARCHAR(10))+']'
FROM Years
ORDER BY Year
DECLARE @sql  nvarchar(max)
SET @sql =
'SELECT *
FROM
(SELECT CustomerID, YEAR(OrderDate)AS OrderYear, TotalDue
FROM Sales.SalesOrderHeader) header
PIVOT
(SUM(TotalDue) FOR OrderYear IN ('+   @years+ ')
) AS pvt
'
exec sp_executesql @sql

All the scripts are available in sky drive for you to download.

Pages: 1 2




Related Articles :

  • No Related Articles Found

No comments yet... Be the first to leave a reply!

Software Reviews | Book Reviews | FAQs | Tips | Articles | Performance Tuning | Audit | BI | Clustering | Developer | Reporting | DBA | ASP.NET Ado | Views tips | | Developer FAQs | Replication Tips | OS Tips | Misc Tips | Index Tuning Tips | Hints Tips | High Availability Tips | Hardware Tips | ETL Tips | Components Tips | Configuration Tips | App Dev Tips | OLAP Tips | Admin Tips | Software Reviews | Error | Clustering FAQs | Performance Tuning FAQs | DBA FAQs |