Common Table Expression
Common Table Expression(CTE)可以看成是一个临时创建的View,他的生命周期仅仅限于当前Context。一旦CTE被创建,你可以将它当成一般的Table,大部分基于Table的操作都可以运用于CTE。下面是创建CTE的语法结构:
E.G.
CTE具有广泛的运用,他往往具有将问题化繁为简的魔力。下面介绍几个典型的运用:
1. 1. 将复杂的Aggregate置于CTE中,将复杂的问题分解为多个步骤。
如果我们现在需要统计每个客户发出的订单数量(相关数据存储于Sales.SalesOrderHeader
中),同时输出客户的个人信息(相关数据存储于Sales.Customer中)。虽然这样的功能很简单,但他体现了一种思想,把一部完成略显复杂的功能进程分解成多个简单的步骤。
用于具有层次结构记录的递归查询
比如一个公司的员工体系就是一个包含上下级关系的具有层次化的树形结构。假设我们有如下一个EMPLOYEE表,通过REPORT_TO体现每个员工的上下级关系(假设Empoyee_Name具有唯一性)。
我们现在的需求是:列出员工A的所有下级。
为了实现这样的一个功能,我们需要以一种特殊的结构来创建CTE:
CTE中主体部分由两个SELECT语句组成( UNION ALL)为界,我们把第一个叫做Anchor Member(AM),AM不会递归,只会执行一次,本例中筛选出了级别最高的A;另一个SELECT语句叫做Recursive Member(RM),RM通过CTE本身和EMPLOYEE表建立连接,所以RM会采用递归的方式执行。
WITH CTE_EMPLOYEE(EMPLOYEE_ID, EMPLOYEE_NAME,REPORT_TO)
AS
(
//只运行一次
SELECT *
FROM dbo.EMPLOYEE
WHERE EMPLOYEE_NAME = 'A'
UNION ALL
//以 UNION ALL为界,下面是RM部分可以运行多次
SELECT dbo.EMPLOYEE.*
FROM dbo.EMPLOYEE
JOIN CTE_EMPLOYEE
ON dbo.EMPLOYEE.REPORT_TO = CTE_EMPLOYEE.EMPLOYEE_ID
)
SELECT *
FROM CTE_EMPLOYEE
WHERE EMPLOYEE_NAME > 'A'
OR EMPLOYEE_NAME < 'A'
我们发现
多个cte:
WITH CategoryAndNumberOfProducts (CategoryID, CategoryName, NumberOfProducts) AS
(
SELECT
CategoryID,
CategoryName,
(SELECT COUNT(1) FROM Products p
WHERE p.CategoryID = c.CategoryID) as NumberOfProducts
FROM Categories c
),
ProductsOverTenDollars (ProductID, CategoryID, ProductName, UnitPrice) AS
(
SELECT
ProductID,
CategoryID,
ProductName,
UnitPrice
FROM Products p
WHERE UnitPrice > 10.0
)
SELECT c.CategoryName, c.NumberOfProducts,
p.ProductName, p.UnitPrice
FROM ProductsOverTenDollars p
INNER JOIN CategoryAndNumberOfProducts c ON
p.CategoryID = c.CategoryID
ORDER BY ProductName WITH CategoryAndNumberOfProducts (CategoryID, CategoryName, NumberOfProducts) AS
(
SELECT
CategoryID,
CategoryName,
(SELECT COUNT(1) FROM Products p
WHERE p.CategoryID = c.CategoryID) as NumberOfProducts
FROM Categories c
),
ProductsOverTenDollars (ProductID, CategoryID, ProductName, UnitPrice) AS
(
SELECT
ProductID,
CategoryID,
ProductName,
UnitPrice
FROM Products p
WHERE UnitPrice > 10.0
)
SELECT c.CategoryName, c.NumberOfProducts,
p.ProductName, p.UnitPrice
FROM ProductsOverTenDollars p
INNER JOIN CategoryAndNumberOfProducts c ON
p.CategoryID = c.CategoryID
ORDER BY ProductName