从SQL Server 2005开始,提供了CTE(Common Table Expression,公用表表达式)的语法支持。html
CTE是定义在SELECT、INSERT、UPDATE或DELETE语句中的临时命名的结果集,同时CTE也能够用在视图的定义中。数据库
在CTE中能够包括对自身的引用,所以这种表达式也被称为递归CTE。express
CTE的优势app
公用表表达式提供的功能其实和视图差很少,可是它不像视图同样把SQL语句保存在咱们的数据库里面。ui
微软官方给出的使用CTE的优点:spa
1.能够编写一个递归查询。code
2.要使用一个相似视图的功能,可是又不想把这个查询SQL语句的定义保存到数据库中。htm
3.要引用一个返回数据的SQL语句屡次,只须要定义一次。blog
使用CTE能够把复杂的SQL语句按照逻辑分红简单独立的几个公用表表达式(CTE),这样的最大优点就是可以提升SQL语句的可读性和可维护性。递归
总结就是,CTE主要能够用于树结构的递归和简化SQL语句,增长可读性和可维护性。
CTE的使用场景
因为业务须要,咱们常常会写一些比较复杂的SQL语句,里面可能会包含不少的JOIN或子查询,要维护和理清这种N多个表的JOIN关系是一件很是头疼的事情,而使用CTE就可使维护和理解复杂的SQL语句变得简单一些。
在开发的时候使用子查询,通常是这种状况:须要从一个复杂的子查询,甚至多级子查询嵌套。在这种状况下,在整个SQL语句里面,不管你是直接写SQL语句仍是把这段SQL语句包装成子查询而后用别名来访问,当业务需求愈来愈变得复杂,你可能随时须要修改这个长且复杂的SQL语句段,而维护这种复杂的、可读性差的SQL语句简直是噩梦。
有了CTE只有,咱们就可使用CTE来定义一个SQL语句,而且为这个SQL语句执行后返回的结果集定义一个别名,接下来就能够经过这个别名来引用这些预先执行返回的数据集,就像使用普通的表同样。
CTE的语法
一个公用表表达式主要包含三个主要部分:
1.CET名称(WITH后面,列名列以前)。
2.列名列(可选)。
3.CET查询语句主体(AS后面括起来的内容)。
with expression_name (column_name, …) as ( -- cte_query_definition cte查询语句定义 )
要注意的是,若是要定义多个表达式,须要用逗号分隔。
使用CTE进行屡次查询
CTE是能够在跟随其后的查询中屡次引用的。
with tmp(id) as ( select id from users where name like '杨%'; ) select * from tmp; select * from orders where userId in (select id from tmp);
使用CTE递归查询树形记录(向上查询父节点或向下查询子节点)
CTE有一个特性就是它是支持递归的,即在CTE的查询语句主体中引用自身。这一特性经常被用在查询树形记录。
with subqry(id, pid, name) as ( select cb.id, cb.pid, cb.namefrom cb where cb.id = '001001001' union all select cb.id, cb.pid, cb.namefrom cb, subqry where cb.id = subqry.pid ) select distinct * from subqry
with subqry(id, pid, name) as ( select cb.id, cb.pid, cb.name from cb where cb.id = '001' union all select cb.id, cb.pid, cb.name from cb, subqry where cb.pid = subqry.id ) select distinct * from subqry
使用CTE的注意事项
1.CTE后面必须紧跟着使用CTE的SQL语句,好比SELECT、INSERT和UPDATE等,不然CTE将失效(直接报错)。
with tmp(id) as ( select id from users where favor = '牛奶'; ) select 1; select * from tmp;
像上面的语句就会报【定义了公用表表达式,但没有使用】的错。
2.CTE后面也能够跟其余的CTE,可是只能使用一个WITH,多个CTE中间用逗号【,】隔开。
with milk(id) as ( select id from users where favor = '牛奶'; ), apple(id) as ( select id from users where favor = '苹果'; ) select id from milk, apple where milk.id = apple.id
3.若是CTE表达式名称与某个实体表或者视图重名,则紧跟在该CTE后面的SQL语句使用的仍然是CTE。
要注意的是,后面再使用该同名就是使用实体表或视图了。
4.CTE能够引用自身,也能够引用在同一个WITH子句中预先定义的CTE,可是不容许前向引用(定义前使用)。
5.不能在CTE_QUERY_DEFINITION(CTE查询语句定义)中使用如下子句:
(1)COMPUTE或COMPUTE BY
(2)ORDER BY(除非指定了TOP 子句)
(3)INTO
(4)带有查询提示的OPTION 子句
(5)FOR XML
(6)FOR BROWSE
6.若是将CTE用于批处理的一部分的语句中,那么在它以前的语句必须以分号结尾。
declare @id int set @id = 0; -- 这里必须以分号结尾 ;with tmp(name) as ( -- 在with前加上分号避免出错 select name from users where unrequitedLove = '静静'; ) select * from tmp;
固然了,一个良好的习惯(技巧)是在写CTE的时候通通在WITH前加上分号【;】,这样就能避免出错,好比上面的语句。
总结
若是常常写查询的话,好比一些统计分析或制做报表,CTE是会常用到的,由于使用起来十分方便,也几乎不会有什么反作用,在必定程度上可以提升开发和维护的效率。另外,其递归属性在树形记录的查询中的应用十分普遍,是一个要好好掌握的语法。
"我仍是很喜欢你,像樵人薄暮,倦鸟归栖。"
原文出处:https://www.cnblogs.com/yanggb/p/11165276.html