特别对于UNION ALL比较有用。因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可。如果WITH AS短语所定义的表名被调用两次以上,则优化器会自动将WITH AS短语所获取的数据放入一个TEMP表里,如果只是被调用一次,则不会。而提示materialize则是强制将WITH AS短语里的数据放入一个全局临时表里。很多查询通过这种方法都可以提高速度。
with
cr as
(
select CountryRegionCode from person.CountryRegion where Name like 'C%'
)
select * from person.StateProvince where CountryRegionCode in (select * from cr)
其中cr是一个公用表表达式,该表达式在使用上与表变量类似,只是SQL Server 2005在处理公用表表达式的方式上有所不同。
with
cr as
(
select CountryRegionCode from person.CountryRegion where Name like 'C%'
)
select * from person.CountryRegion -- 应将这条SQL语句去掉
-- 使用CTE的SQL语句应紧跟在相关的CTE后面 --
select * from person.StateProvince where CountryRegionCode in (select * from cr)
with
cte1 as
(
select * from table1 where name like 'abc%'
),
cte2 as
(
select * from table2 where id > 20
),
cte3 as
(
select * from table3 where price < 100
)
select a.* from cte1 a, cte2 b, cte3 c where a.id = b.id and a.id = c.id
-- table1是一个实际存在的表
with
table1 as
(
select * from persons where age < 30
)
select * from table1 -- 使用了名为table1的公共表表达式
select * from table1 -- 使用了名为table1的数据表
declare @s nvarchar(3)
set @s = 'C%'
; -- 必须加分号
with
t_tree as
(
select CountryRegionCode from person.CountryRegion where Name like @s
)
select * from person.StateProvince where CountryRegionCode in (select * from t_tree)
id node_name parent_id
1 辽宁省 0
id node_name parent_id
2 沈阳市 1
3 大连市 1
id node_name parent_id
4 大东区 2
5 沈河区 2
6 铁西区 2
上述示例准备sql 如下:
if exists (
select *
from sys.tables
where name = 't_tree'
)
drop table dbo.t_tree;
go
create table t_tree
(
id int not null
,node_name varchar(50) null
,parent_id int not null
,[description] varchar(255) null
)
go
insert into t_tree
(
id
,node_name
,parent_id
)
values
(
1
,'辽宁省'
,0
),
(2 ,'沈阳市' ,1),
(3 ,'大连市' ,1),
(4 ,'大东区' ,2),
(5 ,'沈河区' ,2),
(6 ,'铁西区' ,2)
go
public resultset getResultSet(resultset)
{
if(resultset is null)
{
current_resultset =第一个结果集(包含省的记录集)
将结果集的id保存在集合中
getResultSet(current_resultset)
}
current_resultset = 根据id集合中的id值查出当前结果集
if(current_result is null) return resultset
将当前结果集的id保存在集合中
return getResultSet(resultset union all current_resultset)
}
// 获得最终结果集
resultset = getResultSet(null)
[ WITH [ ,n ] ]
::=
expression_name [ ( column_name [ ,n ] ) ]
AS (
CTE_query_definition1 -- 定位点成员(也就是初始值或第一个结果集)
union all
CTE_query_definition2 -- 递归成员
)
with
district as
(
-- 获得第一个结果集,并更新最终结果集
select * from t_tree where node_name= N'辽宁省'
union all
-- 下面的select语句首先会根据从上一个查询结果集中获得的id值来查询parent_id
-- 字段的值,然后district就会变当前的查询结果集,并继续执行下面的select 语句
-- 如果结果集不为null,则与最终的查询结果合并,同时用合并的结果更新最终的查
-- 询结果;否则停止执行。最后district的结果集就是最终结果集。
select a.* from t_tree a, district b
where a.parent_id = b.id
)
select * from district
with
district as
(
select * from t_tree where node_name= N'辽宁省'
union all
select a.* from t_tree a, district b
where a.parent_id = b.id
),
district1 as
(
select a.* from district a where a.id in (select parent_id from district)
)
select * from district1
注:只有“辽宁省”和“沈阳市”有下子节点。
;with district as (
select * from t_tree where node_name= N'辽宁省'
union all
select a.* from t_tree a, district b
where a.id = b.id -- 故意制造无限循环
)
select * from district
OPTION (MAXRECURSION 5) -- 限制特定语句所允许的递归级数,以防止出现无限循环
if exists (
select *
from sys.objects
where name = 'fn_Test'
and type in ('FN' ,'TF')
)
drop function dbo.fn_Test;
go
create function dbo.fn_Test
(
@nodename varchar(50)
)
returns @result table (
id int not null
,node_name varchar(50) null
,parent_id int not null
,[description] varchar(255) null
)
as
begin
;with district as (
select *
from t_tree where node_name = @nodename
union all
select a.*
from t_tree a, district b
where a.parent_id = b.id
),
district1 as (
select *
from district a
where a.id in (select parent_id
from district)
)
insert into @result
(
id
,node_name
,parent_id
,[description]
)
select id
,node_name
,parent_id
,[description]
from district1;
return ;
end;
go
7. 无论参与的 SELECT 语句返回的列的为空性如何,递归 CTE 返回的全部列都可以为空。
8. 如果递归 CTE 组合不正确,可能会导致无限循环。例如,如果递归成员查询定义对父列和子列返回相同的值,则会造成无限循环。可以使用 MAXRECURSION 提示以及在 INSERT、UPDATE、DELETE 或 SELECT 语句的 OPTION 子句中的一个 0 到 32,767 之间的值,来限制特定语句所允许的递归级数,以防止出现无限循环。这样就能够在解决产生循环的代码问题之前控制语句的执行。服务器范围内的默认值是 100。如果指定 0,则没有限制。每一个语句只能指定一个 MAXRECURSION 值。11. 可以在 CTE 中引用远程服务器中的表。如果在 CTE 的递归成员中引用了远程服务器,那么将为每个远程表创建一个假脱机,这样就可以在本地反复访问这些表。
本文转自:在SQL Server中,关于with as使用介绍