Common Table Expressions in SQL Server 2005 ROCK!!!

Published 22 July 05 11:56 AM | James World 

I've been taking a look at a new feature in SQL Server 2005 called "Common Table Expressions" (hereafter CTEs). This is an extra-ordinally powerful extenstion to Transact SQL that removes the need for managing temporary tables in many common scenarios.

In this example code I will set up a typical Employee table that is self-referencing; each Employee has a manager also in the Employee table. I've tested this code on IDW-15 (June CTP) only, but its been in the builds for a while so should work on the April CTP with no problems.

Here is the setup code:

USE master
GO
-- Drop the database if it already exists
IF EXISTS (
SELECT name
FROM sys.databases
WHERE name = N'CTE_Rank_Demo'
)
DROP DATABASE CTE_Rank_Demo
GO
CREATE DATABASE CTE_Rank_Demo
GO
USE CTE_Rank_Demo
GO
-- =========================================
-- Create demo table and data
-- This is a bunch of employees, each
-- having a manager which is a fk back
-- to the table.
-- =========================================
CREATE TABLE Employee
(
id
int IDENTITY CONSTRAINT PK_Employee_id PRIMARY KEY CLUSTERED,
name nvarchar(50),
mgr_id
int CONSTRAINT FK_Employee_mgr_id FOREIGN KEY REFERENCES Employee(id),
country
varchar(2),
age
int,
sales
int
)
GO
-- Create some sample data
INSERT Employee VALUES('Steve', NULL, 'UK', 50, 200)
INSERT Employee VALUES('James', 1, 'UK', 30, 500)
INSERT Employee VALUES('Neil', 1, 'US', 35, 600)
INSERT Employee VALUES('Blair', 2, 'AU', 41, 250)
INSERT Employee VALUES('Ken', 1, 'DE', 38, 100)
INSERT Employee VALUES('Paul', 3, 'FR', 36, 480)
INSERT Employee VALUES('Adrian', 3, 'FR', 32, 290)
INSERT Employee VALUES('Ian', 4, 'UK', 27, 120)
INSERT Employee VALUES('Matt', 7, 'DE', 34, 10)
GO

OK, now lets look at a simple CTE.

-- 1. A really simple and not very useful
-- CTE example to introduce the syntax
-- The WITH clause introduces a CTE and
-- we define an in-memory result table
-- called T
WITH T(id, sales)
AS
(
SELECT id, sales FROM
Employee
)
-- We can now join to the in-memory result table
SELECT
E.id, T.sales
FROM
Employee E INNER JOIN T ON
E.id = T.id
GO

You get back a list of employees and their sales total.

Big deal, we could have just done that in one simple query anyway. So lets look at something more interesting... recursive CTEs! Here is a sample that gets back a list of an employee and all employees that reports to him and all employees that report to them... etc. Basically the subtree of the orgtree rooted at a particular employee.

-- 2. Use a common table expression
-- with recursion to get Neil and
-- all employees he is responsible for
-- A recusive CTE is denoted by two queries
-- joined by a UNION ALL operator and
-- the second query references the CTE table
-- itself.
-- The WITH clause introduces a CTE and
-- we define an in-memory result table
-- called Manager
WITH Manager(id, name, mgr_id)
AS
(
-- Neil will be the first row in this table
SELECT
id, name
, mgr_id
FROM
Employee WHERE
id=3
-- To use recusion we must say UNION ALL
UNION ALL
-- Now the following select table will recurse
-- At the first level of recursion it will find Neil's
-- direct reports and insert these into the
-- Manager table. Then it will be called again
-- on each of the the new rows added to the table to find
-- their direct reports and so on...
SELECT
Employee.id,
Employee.name,
Employee.mgr_id
FROM
Employee INNER JOIN
Manager
ON
Employee.mgr_id = Manager.id
)
-- Now we can select out all the employees
-- we found from the in-memory table
SELECT
*
FROM
Manager
GO

Awesome! Now let's look at a really cool example... this query uses aggregates to return the total sales of each employee and all the employees below them...

-- 3. Now lets use a recursive CTE to
-- get the total sales of each
-- employee and all their reports!!!
-- This really shows the power of CTEs
WITH Manager(id, name, mgr_id, sales)
AS
(
-- Start by selecting *all* employees rather
-- than just one.
SELECT
id, name
, mgr_id, sales
FROM
Employee
UNION ALL
-- This is almost the same as before,
-- but now we are recording the name
-- of the manager rather than the employee
-- name and copying that name as we
-- recurse so that each row is tied back to
-- the originating Employee in the first query
-- of the CTE.
SELECT
Employee.id,
name
= Manager.name,
Employee.mgr_id,
Employee.sales
FROM
Employee INNER JOIN
Manager
ON
Employee.mgr_id = Manager.id
)
-- Now we can use an aggregate expression grouped
-- by the manager name to find their total sales
SELECT
name, SUM(sales) as
total_sales
FROM
Manager
GROUP BY
name
ORDER BY
total_sales
DESC
GO

I think you'll agree than CTEs are going to be very popular indeed!

Comments

# James World Common Table Expressions in SQL Server 2005 ROCK | Outdoor Decor said on June 19, 2009 12:31 AM:

PingBack from http://outdoordecoration.info/story.php?id=4599

# James World Common Table Expressions in SQL Server 2005 ROCK | adirondack chairs said on June 19, 2009 4:59 AM:

PingBack from http://adirondackchairshub.info/story.php?id=3669

Anonymous comments are disabled

Search

This Blog

Syndication

Page view tracker