WITH AS短语,也叫做子查询部分(subqueryfactoring),定义一个SQL片断,该SQL片断会被整个SQL语句所
用到。有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNIONALL的不同部分,作为提供数据的部分。特
别对于UNIONALL比较有用。因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太
高,所以可以使用WITHAS短语,则只要执行一遍即可。如果WITH AS短语所定义的表名被调用两次以上,则优化器会
自动将WITHAS短语所获取的数据放入一个TEMP表里,如果只是被调用一次,则不会。而提示materialize则是强制将
WITHAS短语里的数据放入一个全局临时表里。很多查询通过这种方法都可以提高速度。
做过报表或者维护过报表的人都知道,报表最让人恶心的就是屡不清的sql和乌龟一样的速度。嵌套查询,尤其
是多重嵌套是最让人恶心的,前段时间维护一个报表,一百多行的sql,也不知道是那个大神,用一句sql搞定的,各
种嵌套,虽然开发时没什么感觉,可是维护人员就彻底晕菜了,根本就找不到那是那,最后没办法只能跟组长申请重
新开发吧,没办法维护啊,根本就不存在可读性这一说。还有就是表变量查询,也就是我们常说的借助临时表,这样
虽然提高了可读性和维护性,但是增加了额外的I/O开销,如果数据量大且频繁查询时,就会出现乌龟一般的查询速
度。
数据量小或者查询次数少的时候这两种方式没有什么问题,但我觉得为了提供效率和方便后面的人员维护,让后
面维护的人喜欢你开发的报表,我们可以采用CTE(CommonTable Expression) ,即公用表表达式。它提高SQL语句的
可维护性,同时,CTE要比表变量的效率高得多。
<span style="font-size:18px;">[ WITH<common_table_expression> [ ,n ] ] <common_table_expression>::= expression_name [ ( column_name [ ,n ] ) ] AS ( CTE_query_definition )</span>
简单实例:
<span style="font-size:18px;">withtest_CTE(id,salary) as ( select id,max(salary) from test group by id ) select * fromtest_cte</span>
由上面例题可以看出:CTE 由表示 CTE的表达式名称、可选列列表和定义 CET 的查询组成。
1.CTE后面必须直接跟使用CTE的SQL语句(如select、insert、update等),否则,CTE将失效。如下面的SQL语句将
无法正常使用CTE:
<span style="font-size:18px;">with Test_CTEas ( select code fromTenement.PropertyProject where CnName like '%大连%' ) select * fromTenement.PropertyProduct -- 应将这条SQL语句去掉 --使用CTE的SQL语句应紧跟在相关的CTE后面 -- select* from Tenement.PropertyProject where code in (select * from Test_CTE) </span>
2.CTE后面也可以跟其他的CTE,但只能使用一个with,多个CTE中间用逗号(,)分隔,如下面的SQL语句所示:
<span style="font-size:18px;">with Project as ( select * from PropertyProject where CnName like '大连%' ), House as ( select * from Tenement.PropertyHouse where roomNo > 20 ), Unit as ( select * from Tenement.[PropertyUnit]where CnName like '%远洋自然%' ) selectHouse .* from Project a, Houseb, Unit c where a.code = b.projectCode and a.code = c.projectCode </span>
3.如果CTE的表达式名称与某个数据表或视图重名,则紧跟在该CTE后面的SQL语句使用的仍然是CTE,当然,后面的
SQL语句使用的就是数据表或视图了,如下面的SQL语句所示:
<span style="font-size:18px;">-- Project是一个实际存在的表 with Project as ( select * from PropertyProject where CnName like '大连%' ) select * from Project-- 使用了名为Project 的公共表表达式 select * from Project-- 使用了名为Project 的数据表 </span>
4. CTE可以引用自身,也可以引用在同一 WITH 子句中预先定义的 CTE。不允许前向引用。
5. 不能在CTE_query_definition 中使用以下子句:
(1)COMPUTE 或 COMPUTEBY
(2)ORDER BY(除非指定了 TOP子句)
(3)INTO
(4)带有查询提示的 OPTION子句
(5)FOR XML
(6)FOR BROWSE
6. 如果将 CTE用在属于批处理的一部分的语句中,那么在它之前的语句必须以分号结尾,如下面的SQL所示:
<span style="font-size:18px;">declare @snvarchar(3) set @s = '大连%' ; -- 必须加分号 with Project as ( select Code from PropertyProject where CnName like @s ) select * from PropertyProject where Code in (select * fromProject) </span>
1.使用 CTE 可以获得提高可读性和轻松维护复杂查询的优点。
2.查询可以分为单独块、简单块、逻辑生成块。这些简单块可用于生成更复杂的临时 CTE,直到生成最终结果集。
CTE在一定程度上解决了嵌套查询带来的可读性差以及表变量查询造成的查询效率问题,但它不能解决所有的问
题,只能说当数据量大,并且逻辑比较复杂时,CTE比这两种方式更有优势。当然这个年底傻傻的写sql是很可耻的。