表表达式是一种命名的查询表达式,表明一个有效地关系表。能够像其余表同样,在数据处理中使用表表达式。html
SQL Server支持四种类型的表表达式:派生表,公用表表达式,视图和内联表值函数。sql
为何使用表表达式:数据库
1.使用表表达式的好处是逻辑方面,在性能上没有提高。模块化
2.经过模块化的方法简化问题的解决方案,规避语言上的某些限制。在外部查询的任何字句中均可以引用在内部查询的SELECT字句中分配的列别名。好比在SELECT字句中起的别名,不能在WHERE,group by等字句(逻辑顺序位于SELECT字句以前的字句)中使用,经过表表达式能够解决这类问题函数
派生表(也称为表子查询)是在外部查询的FROM子句中定义的,只要外部查询一结束,派生表也就不存在了。post
派生表能够简化查询,避免使用临时表。相比手动生成临时表性能更优越。派生表与其余表同样出如今查询的FROM子句中性能
select * from (select * from athors) temp
temp 就是派生表大数据
派生出来的表必需要是一个有效的表.所以,它必须遵照如下几条规则:优化
1. 全部列必需要有名称ui
2. 列名称必须是要惟一
3. 不容许使用ORDER BY(除非指定了TOP)
派生表:好比要查找一个叫张铁牛的人的信息,咱们知道他是男性,为了缩小查找范围我把全部的男性都找出来,而后从这些男性中里面再去找张铁牛.这里男性的集合就至关于派生表,转成sql语句:
select 姓名,住址,身份证 from (select * from 表名 where 性别='男性') temp where 姓名='张铁牛'
(这里只是为了举例子),这里的 temp这个数据集就是派生表,它是虚表,在数据库中不存在的,是咱们构建的,在这里的目的是为了缩小数据的查找范围.
分配列别名(建议使用内嵌别名形式)
SELECT orderyear, COUNT(DISTINCT custid) AS numcusts FROM (SELECT YEAR(orderdate), custid FROM Sales.Orders) AS D(orderyear, custid) GROUP BY orderyear;
使用参数
DECLARE @empid AS INT = 3; SELECT orderyear, COUNT(DISTINCT custid) AS numcusts FROM (SELECT YEAR(orderdate) AS orderyear, custid FROM Sales.Orders WHERE empid = @empid) AS D GROUP BY orderyear;
嵌套
若是需要用一个自己就引用了某个派生表的查询去定义另外一个派生表,最终获得的就是嵌套派生表。
例子:查询每一年处理客户数超过70的订单年度和每一年所处理的客户数量。
方案一:咱们用第一节中单表查询查询出结果
SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS numcusts FROM Sales.Orders GROUP BY YEAR(orderdate) HAVING COUNT(DISTINCT custid) > 70;
方案二:嵌套派生表
SELECT orderyear, numcusts FROM (SELECT orderyear, COUNT(DISTINCT custid) AS numcusts FROM (SELECT YEAR(orderdate) AS orderyear, custid FROM Sales.Orders) AS D1 GROUP BY orderyear) AS D2 WHERE numcusts > 70;
嵌套查询看起来很是复杂,嵌套查询也是很容易产生问题的一个方面。在这个例子中,使用嵌套派生表的目的是为了重用列别名。可是,因为嵌套增长了代码的复杂性,因此对于本例考虑使用方案一。
多个引用
SELECT Cur.orderyear, Cur.numcusts AS curnumcusts, Prv.numcusts AS prvnumcusts, Cur.numcusts - Prv.numcusts AS growth FROM (SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS numcusts FROM Sales.Orders GROUP BY YEAR(orderdate)) AS Cur LEFT OUTER JOIN (SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS numcusts FROM Sales.Orders GROUP BY YEAR(orderdate)) AS Prv ON Cur.orderyear = Prv.orderyear + 1;
缺点:咱们看到其实咱们是对同一张表进行联接,可是须要将代码定义多遍,这无疑形成代码的混乱和冗余。
公用表表达式是和派生表类似的另外一种形式的表表达式,可是公用表表达式具备一些优点。
公用表表达式和派生表同样,前面须要遵照的规则对公用表表达式一样适用。当外部查询结束,公用表表达式的生命周期就结束了。
其实CTE的做用就至关于子查询。
内联格式:别名写在内部查询中
WITH C AS ( SELECT YEAR(orderdate) AS orderyear, custid FROM Sales.Orders ) SELECT orderyear, COUNT(DISTINCT custid) AS numcusts FROM C GROUP BY orderyear;
外联格式:列的别名写在外部查询中
WITH C(orderyear, custid) AS ( SELECT YEAR(orderdate), custid FROM Sales.Orders ) SELECT orderyear, COUNT(DISTINCT custid) AS numcusts FROM C GROUP BY orderyear;
使用参数
DECLARE @empid AS INT = 3; WITH C AS ( SELECT YEAR(orderdate) AS orderyear, custid FROM Sales.Orders WHERE empid = @empid ) SELECT orderyear, COUNT(DISTINCT custid) AS numcusts FROM C GROUP BY orderyear;
定义多个CTE
CTE和派生表相关具备如下优点:
若是要在一个CTE中引用另外一个CTE,不需要像派生表那样进行嵌套,只须要在同一个WITH字句中定义多个CTE,并用逗号把它们分隔开。每一个CTE能够引用在它前面定义的全部CTE,而外部查询则能够引用全部CTE。
因为CTE只能在接下来一条语句中使用,所以,当须要接下来的一条语句中引用多个CTE时,能够定义多个,中间用逗号分隔,下面是一次定义多个CTE的例子:
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 WHERE numcusts > 70;
CET中的多个引用
公用表表达式的好处之一是能够在接下来一条语句中屡次引用:
WITH CTE_Test AS ( SELECT * FROM Person_1 ) SELECT * FROM CTE_Test AS a --第一次引用 INNER JOIN CTE_Test AS b --第二次引用 ON a.Id = b.Id ORDER BY a.Id DESC
WITH YearlyCount AS ( SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS numcusts FROM Sales.Orders GROUP BY YEAR(orderdate) ) SELECT Cur.orderyear, Cur.numcusts AS curnumcusts, Prv.numcusts AS prvnumcusts, Cur.numcusts - Prv.numcusts AS growth FROM YearlyCount AS Cur LEFT OUTER JOIN YearlyCount AS Prv ON Cur.orderyear = Prv.orderyear + 1;
递归CET
CTE 能够包含对自身的引用,这种表达式被称为递归公用表表达式。
;with district as ( select * from ta where [name]=N'河北省' union all select a.* from ta a inner join district b on a.parentid=b.id ) select * from district
CTE是一种十分优雅的存在。CTE所带来最大的好处是代码可读性的提高,这是良好代码的必须品质之一。使用递归CTE能够更加轻松愉快的用优雅简洁的方式实现复杂的查询。
CET优势:
相对于派生表最主要的优点在于能够一次定义,屡次使用。
CET大部分地方能够代替临时表。CTE最优秀的地方是在实现递归操做,和替代绝大部分游标的功能。
CET后面必须直接跟使用CTE的SQL语句(如select、insert、update等),不然,CET将失效。可是临时表一直存在,除非drop掉。
CET缺点:
对于大数据量,因为CET不能建索引,因此明显比临时表差。我给开发的建议是少于1万数据的话,CET和表变量就不要用于作暂存数据的功能。而改用临时表。
数据量大时,CET的性能要比临时表差不少(即便临时表不建索引)
CET要比表变量效率高得多!
临时表和表变量的选择
咱们对于较小的数据或者是经过计算出来的推荐使用表变量。若是数据的结果比较大,在代码中用于临时计算,在选取的时候没有什么分组的聚合,就能够考虑使用表变量。
通常对于大的数据结果,或者由于统计出来的数据为了便于更好的优化,咱们就推荐使用临时表,同时还能够建立索引,因为临时表是存放在Tempdb中,通常默认分配的空间不多,须要对tempdb进行调优,增大其存储的空间。
表变量实际上使用了临时表,从而增长了额外的I/O开销,所以,表变量的方式并不太适合数据量大且频繁查询的状况。
1.视图和派生表和CTE的区别和共同点
区别:
派生表和CTE不可重用:只限于在单个语句的范围内使用,只要包含这些表表达式的外部查询完成操做,它们就消失了。
视图和内联表值函数是可重用的:它们的定义存储在一个数据对象中,一旦建立,这些对象就是数据库的永久部分;只有用删除语句显示删除或用右键删除,它们才会从数据库中移除。
共同点:
在不少方面,视图和内联表值函数的处理方式都相似于派生表和CTE。当查询视图和内联表值函数时,SQL Server会先扩展表表达式的定义,再直接查询底层对象。
建立一个视图:
IF OBJECT_ID('Sales.USACusts') IS NOT NULL DROP VIEW Sales.USACusts; GO CREATE VIEW Sales.USACusts AS SELECT custid, companyname, contactname, contacttitle, address, city, region, postalcode, country, phone, fax FROM Sales.Customers WHERE country=N'USA'; GO
使用该视图:
SELECT * FROM Sales.USACusts;
什么是内联表值函数
一种可重用的表表达式,可以支持输入参数。除了支持输入参数之外,内联表值函数在其余方面都与视图类似。
内嵌表值函数是支持输入参数的可重复使用的表表达式。除了支持输入参数以外的其余全部方面都和视图相似。咱们来看下怎么建立内嵌表值函数。
下面演示如何建立函数:
IF OBJECT_ID('dbo.fn_GetCustOrders') IS NOT NULL DROP FUNCTION dbo.fn_GetCustOrders; GO CREATE FUNCTION dbo.fn_GetCustOrders (@cid AS INT) RETURNS TABLE AS RETURN SELECT orderid, custid, empid, orderdate, requireddate, shippeddate, shipperid, freight, shipname, shipaddress, shipcity, shipregion, shippostalcode, shipcountry FROM Sales.Orders WHERE custid=@cid; GO
如何使用函数:
SELECT orderid, custid FROM dbo.fn_GetCustOrders(1) AS CO;
小结
借助表表达式能够简化代码,提升代码的可维护性,还能够封装查询逻辑。
当须要使用表表达式,并且不计划重用它们的定义时,可使用派生表或CTE。与派生表相比,CTE具备两个优势:CTE不用像派生表那样嵌套使用,此外,还能够引用同一CTE的多个实例,也派生表不能这么用。
当须要定义可重用的表表达式时,可使用视图和内联表值函数。若是不需要支持输入参数,则使用视图,相反则使用内联表值函数。
(1)表表达式能够简化代码,提升代码的可维护性和封装查询逻辑。
(2)当须要使用表表达式而且不打算重复使用其定义时,可使用派生表或CTE,而CTE对派生表具备更多优点不须要像派生表那样嵌套CTE,使用CTE使代码更加模块化和便于维护,此外,还能够引用同一个CTE的多个实例,这一点是派生表没法实现的。
(3)当须要使用表表达式而且须要定义可重复使用的表表达式时,可使用视图或内嵌表值函数,当不须要支持输入参数时,可使用视图,不然,应当使用内嵌表值函数(TVF)。
APPLY运算符是一个非标准标准运算符。APPLY运算符对两个输入进行操做,其中右边的表能够是一个表表达式。
CROSS APPLY:把右边表达式应用到左表中的每一行,再把结果集组合起来,生成一个统一的结果表。和交叉链接类似
OUTER APPLY:把右边表达式应用到左表中的每一行,再把结果集组合起来,而后添加外部行。和左外联接中增长外部行的那一步类似
https://www.cnblogs.com/kissdodog/archive/2013/06/24/3153012.html
https://blog.csdn.net/miqi770/article/details/51505720
https://www.cnblogs.com/janneystory/p/5623019.html
http://www.cnblogs.com/jackson0714/p/TSQLFundamentals_04_part1.html