基础很重要~~04.表表达式-上篇
概述:
本篇主要是对表表达式中派生表和公用表表达式基础的总结。
表表达式包含四种:
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/
关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!