概述:
本篇主要是对表表达式中派生表和公用表表达式基础的总结。
表表达式包含四种:
1.派生表
2.公用表表达式
3.视图
4.内联表值函数
本篇是表表达式的上篇,只会讲到派生表和公用表表达式,下篇会讲到视图和内联表值函数。
下面是表表达式的思维导图:
一、派生表
1.用法:
使用地方:外部查询的FROM字句中定义
存在范围:外部查询一结束,派生表就不存在
语法:派生表的查询语句写在括号里面,括号外面跟着AS关键字和派生表的名称。
SELECT columns FROM ( SELECT columns FROM Table ) AS TABLE_1
例子:
1
2
3
4
5
|
SELECT
*
FROM
(
SELECT
orderdate
FROM
Sales.Orders
WHERE
orderdate =
'20070101'
)
AS
O1
|
定义了一个O1的派生表,返回所有订单日期='20070101'的订单,外部查询返回派生表的所有行。
在这个例子中,其实不需要派生表,只是为了演示派生表的语法。
2.分配列别名
例子:
下面的SQL语句是无效的:
1
2
3
|
SELECT
YEAR
(orderdate)
AS
orderyear
FROM
Sales.Orders
GROUP
BY
orderyear
|
方案一:SELECT字句和GROUP BY字句中都定义YEAR(orderdate)
1
2
3
|
SELECT
YEAR
(orderdate)
AS
orderyear
FROM
Sales.Orders
GROUP
BY
YEAR
(orderdate)
|
方案二:派生表
因为GROUP BY语句的是在SELECT字句之前执行的,所以GROUP BY字句不能引用SELECT字句中定义的别名orderyear。
解决办法是使用表表达式:
1
2
3
4
5
6
|
SELECT
orderyear
FROM
(
SELECT
YEAR
(orderdate)
AS
orderyear
FROM
Sales.Orders
)
AS
O1
GROUP
BY
orderyear
|
结果:
派生表O1是字段orderyear的集合,外部查询SELECT字句和GROUP BY字句可以引用派生表O1的orderyear字段。
SQL SERVER在执行时会扩展表表达式的定义,以便直接访问底层对象。扩展后,与方案一类似。
一般来说,表表达式既不会对性能产生正面影响,也不会对性能产生负面影响。
3.使用参数
在派生表的查询中,可以引用参数。
例子:
基于上面的例子,我们定义了一个标量@orderid,在派生表查询语句中的WHERE字句中引用这个参数。
1
2
3
4
5
6
7
8
|
--定义参数@orderid的值等于,参数类型为INT类型
DECLARE
@orderid
AS
INT
= 10248
SELECT
orderyear
FROM
(
SELECT
FROM
Sales.Orders
WHERE
orderid = @orderid
)
AS
O1
GROUP
BY
orderyear
|
4.嵌套
如果须要用一个本身就引用了某个派生表的查询去定义另一个派生表,最终得到的就是嵌套派生表。
例子:查询用于返回订单年份和该年处理的客户数,要求每个订单年份处理的客户数要多于10人
方案一:我们用第一节中单表查询查询出结果
1
2
3
4
5
6
|
SELECT
YEAR
(orderdate)
AS
orderyear ,
COUNT
(
DISTINCT
custid)
AS
numcuts
FROM
Sales.Orders
GROUP
BY
YEAR
(orderdate)
HAVING
COUNT
(
DISTINCT
custid) > 10
|
方案二:嵌套派生表
1
2
3
4
5
6
7
8
9
10
11
|
SELECT
orderyear ,
numcuts
FROM
(
SELECT
orderyear ,
COUNT
(
DISTINCT
custid)
AS
numcuts
FROM
(
SELECT
YEAR
(orderdate)
AS
orderyear ,
custid
FROM
Sales.Orders
)
AS
O1
GROUP
BY
orderyear
)
AS
O2
WHERE
numcuts > 10
|
嵌套查询看起来非常复杂,嵌套查询也是很容易产生问题的一个方面。在这个例子中,使用嵌套派生表的目的是为了重用列别名。但是,由于嵌套增加了代码的复杂性,所以对于本例考虑使用方案一。
5.练习题
1.写一个查询,为每个雇员返回其订单日期最近的所有订单(用派生表)
期望结果:
本题分两个步骤:
1.可以先查询出每个雇员的订单的最大日期,生成派生表O1
2.O1与Sales.Orders表进行关联,查询出每个雇员处理过的订单日期等于最大的订单日期的所有订单。
1
2
3
4
5
6
7
8
9
10
11
|
SELECT
O2.empid ,
O2.orderdate ,
orderid ,
custid
FROM
(
SELECT
empid ,
MAX
(orderdate)
AS
orderdate
FROM
Sales.Orders
GROUP
BY
empid
)
AS
O1
INNER
JOIN
Sales.Orders
AS
O2
ON
O1.empid = O2.empid
AND
O1.orderdate = O2.orderdate
|
二、公用表表达式
公用表表达式是和派生表相似的另一种形式的表表达式,但是公用表表达式具有一些优势。
1.语法:
内联格式:别名写在内部查询中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
WITH
表名
AS
(
内部查询
)
外部查询<br>
例子:
WITH
O1
AS
(
SELECT
custid,companyname
FROM
Sales.Customers
)
SELECT
*
FROM
O1
|
外联格式:列的别名写在外部查询中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
WITH
表名(别名)
AS
(
内部查询
)
外部查询
例子:
WITH
O1(custid_1,companyname_1)
AS
(
SELECT
custid,companyname
FROM
Sales.Customers
)
SELECT
*
FROM
O1
|
2.用法
公用表表达式和派生表一样,前面需要遵守的规则对公用表表达式同样适用。当外部查询结束,公用表表达式的生命周期就结束了。
3.使用参数
和派生表一样,可以引用参数。
例子:
1
2
3
4
5
6
7
8
9
|
DECLARE
@custid
AS
INT
= 10248;
WITH
O1(custid_1,companyname_1)
AS
(
SELECT
custid,companyname
FROM
Sales.Customers
WHERE
@custid = @custid
)
SELECT
*
FROM
O1
|
4.定义多个CTE
CTE和派生表相比具有以下优势:
如果要在一个CTE中引用另一个CTE,不须要像派生表那样进行嵌套,只需要在同一个WITH字句中定义多个CTE,并用逗号把它们分隔开。每个CTE可以引用在它前面定义的所有CTE,而外部查询则可以引用所有CTE。
如下面的例子,将嵌套派生表改为多个CTE:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
WITH
C1
AS
(
SELECT
YEAR
(orderdate)
AS
orderyear ,
custid
FROM
Sales.Orders
),
C2
AS
(
SELECT
orderyear ,
COUNT
(
DISTINCT
custid)
AS
numcusts
FROM
C1
GROUP
BY
orderyear
)
SELECT
orderyear ,
numcusts
FROM
C2
|
5.练习题
为每个订单按照orderdate、orderid的顺序来计算其行号,并返回行号在11~20之间的行。
期望结果:
本题分两个步骤:
1.查询出基于orderdate,orderid排序的结果集,然后将这个查询语句用CTE来表示
2.查询第一步结果集中11~20之间的行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
WITH
O1
AS
(
SELECT
orderid ,
orderdate ,
custid ,
empid ,
ROW_NUMBER() OVER (
ORDER
BY
orderdate, orderid )
AS
rownum
FROM
Sales.Orders
)
SELECT
*
FROM
O1
WHERE
rownum
BETWEEN
11
AND
20
|
参考资料:
《SQL2008技术内幕:T-SQL语言基础》
原文来自:基础很重要~~04.表表达式-上篇
作 者: Jackson0714
出 处:http://www.cnblogs.com/jackson0714/
关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!