select*from(SELECT custid,ordermonth,qty
FROM Sales.CustOrders)as CustOrders
5.1.1 分配列别名
内联别名
select orderyear,count(distinct custid)as numcusts
from(SELECTyear(orderdate)as orderyear,custid
FROM Sales.Orders)as D
groupby orderyear;
外联别名
select orderyear,count(distinct custid)as numcusts
from(SELECTyear(orderdate),custid
FROM Sales.Orders)as D(orderdate,custid)groupby orderyear;
5.1.2 嵌套
容易出问题
select orderyear,numcusts
from(select orderyear,count(distinct custid)as numcusts
from(SELECTyear(orderdate)as orderyear,custid
FROM Sales.Orders)as D1
groupby orderyear)as D2
where numcusts >70;
5.1.3 派生表的多引用
当需要多次引用同一个派生表时需要重复定义
select cur.orderyear,
cur.numcusts as curnumcusts,prv.numcusts as prvnumcusts,
cur.nmcusts - prv.numcusts as growth
from(SELECTyear(orderdate)as orderyear,count(distinct custid)as numcusts
FROM Sales.Orders
groupbyyear(orderdate))as cur
leftjoin(SELECTyear(orderdate)as orderyear,count(distinct custid)as numcusts
FROM Sales.Orders
groupbyyear(orderdate))as prv
on cur.orderyear = prv.orderyear +1;
5.2 公用表表达式
ANSI
5.2.1 定义格式
with usacusts /*CTE_name*/as(-- inner_query_defining_CTEselect custid, companyname
from sales.customers
where countr ='USA')-- outer_query_against_CTEselect*from usacusts;
5.2.2 不需要嵌套
with D1 AS(SELECTyear(orderdate)as orderyear,custid
FROM Sales.Orders
),
D2 AS(select orderyear,count(distinct custid)as numcusts
from D1
groupby orderyear
)select orderyear,numcusts
from D2 where numcusts >70;
5.2.3 多引用不需要重复
每个CTE可以引用在它之前定义的所有CTE
外部查询可以引用所有CTE
with yearlycount as(SELECTyear(orderdate)as orderyear,count(distinct custid)as numcusts
FROM Sales.Orders
groupbyyear(orderdate))select cur.orderyear,
cur.numcusts as curnumcusts,prv.numcusts as prvnumcusts,
cur.nmcusts - prv.numcusts as growth
from yearlycount as cur
leftjoin yearlycount as prv
on cur.orderyear = prv.orderyear +1;
5.2.4 递归
至少包含两个查询
定位点成员
递归成员
对【CTE_name】的引用代表的是在上一个执行序列中的结果集
第一次调用递归成员时,其中对【CTE_name】的引用代表的是定位点成员的执行结果
定位点成员只被调用一次
递归查询的中间结果保存在temp数据库中
-- 查询Id=2的员工及其直接下属和间接下属with empscte as(-- anchor_member-- 只被调用一次select empid,mgrid,firstname,lastname
from hr.employees
where empid=2unionall-- recursive_member-- 对CTE_name的引用代表的是在上一个执行序列中的结果集select c.empid,c.mgrid,c.firstname,c.lastname
from empscte as p
join hr.employees as c
on c.mgrid = p.empid
)select empid,mgrid,firstname,lastname
from empscte;
最大递归调用次数
SQL Server默认为100
可在外部查询的最后设置最大递归次数
0为不限制
-- 查询Id=2的员工及其直接下属和间接下属with empscte as(-- anchor_member-- 只被调用一次select empid,mgrid,firstname,lastname
from hr.employees
where empid=2unionall-- recursive_member-- 对CTE_name的引用代表的是在上一个执行序列中的结果集select c.empid,c.mgrid,c.firstname,c.lastname
from empscte as p
join hr.employees as c
on c.mgrid = p.empid
)select empid,mgrid,firstname,lastname
from empscte option(maxrecursion 200);
5.3 视图
存储在数据库中,可复用
视图的列是在编译视图时进行枚举的,新增加的列不会自动加到视图中
sp_refreshview
当视图是通过select * 创建的,可以通过该存储过程刷新元数据
5.3.1 视图的定义
if object_id('sales.usacusts')isnotnulldropview sales.usacusts;
go
createview sales.usacusts
asselect custid,companyname, contactname, contacttitle
, address,city,region,postalcode,country,phone,fax
from sales.customers
where country ='USA';
go
alterview sales.usacusts with encryption
asselect custid,companyname, contactname, contacttitle
, address,city,region,postalcode,country,phone,fax
from sales.customers
where country ='USA';
go
5.3.2.2 schemabinding
将对象和列的架构绑定到引用其对象的架构
即被引用的对象不能删除,被引用的列也不能删除或修改
要求
视图不是使用select * 进行查询
对象名称为完整对象名称
alterview sales.usacusts with schemabinding
asselect custid,companyname, contactname, contacttitle
, address,city,region,postalcode,country,phone,fax
from sales.customers
where country ='USA';
go
5.3.2.3 check option
默认情况下,可以向视图中插入不满足视图过滤条件的数据
设置check option后,则不允许
alterview sales.usacusts with schemabinding
asselect custid,companyname, contactname, contacttitle
, address,city,region,postalcode,country,phone,fax
from sales.customers
where country ='USA'withcheckoption;
go
5.4 内联表值函数
可复用的表表达式
可支持输入参数,可看作参数化的视图
if object_id('dbo.fn_getcustorders')isnotnulldropfunction dbo.fn_getcustorders;
go
createfunction dbo.fn_getcustorders
(@cidasint)returnstableasreturnselect orderid,custid,empid,orderdate
from sales.orders
where custid =@cid;
go
select orderid,custid
from dbo.fn_getcustorders(1)as co;
5.5 apply运算符
效果类似 cross join
区别
apply中右表表达式可以是相关子查询
根据左表中的行动态生成右边的派生表
join中右表表达式必须是独立子查询
分类
cross apply
如果右表表达式返回空集,则左表相应数据不显示
outer apply
如果右表表达式返回空集,则左表相应数据会作为外部行添加到结果中
相当于外联接
select c.custid,a.orderid,a.orderdate
from Sales.Customers as c
crossapply(selecttop3 orderid,empid,orderdate,requireddate
from Sales.Orders as o
where o.custid=c.custid
orderby orderdate desc,orderid desc)as a;