您好,欢迎访问一九零五行业门户网

SQL2005 学习笔记 公用表表达式(CTE)

公用表表达式是sql server2005新增加的一个非常好用的功能。
公用表表达式 (cte) 可以认为是在单个 select、insert、update、delete 或 create view 语句的执行范围内定义的临时结果集。
cte 与派生表类似,具体表现在不存储为对象,并且只在查询期间有效。
与派生表的不同之处在于,cte 可自引用,还可在同一查询中引用多次。
cte可用于:
1.创建递归查询(我个人认为cte最好用的地方)
2.在同一语句中多次引用生成的表
cte优点:
使用 cte 可以获得提高可读性和轻松维护复杂查询的优点。
查询可以分为单独块、简单块、逻辑生成块。之后,这些简单块可用于生成更复杂的临时 cte,直到生成最终结果集。
cte可使用的范围:
可以在用户定义的例程(如函数、存储过程、触发器或视图)中定义 cte。
下面看一个简单的cte例题:
把test表中salary最大的id记录保存在test_cte中,再调用
代码如下:
with test_cte(id,salary)
as
(
select id ,max(salary)
from test
group by id
)
select * from test_cte
由上面例题可以看出:
cte 由表示 cte 的表达式名称、可选列列表和定义 cet 的查询组成。
定义 cte 后,可以在 select、insert、update 或 delete 语句中对其进行引用,就像引用表或视图一样。
简单的说cte可以替代临时表和表变量的功能。
我个人认为cte最好用的地方是创建递归查询,下面演示一下这功能:
现有一数据结构如下:
这些数据存放在表co_itemnameset中,表结构和部分数据如下:
itemid parentitemid itemname
2 0 管理费用
3 0 销售费用
4 0 财务费用
5 0 生产成本
35 5 材料
36 5 人工
37 5 制造费用
38 35 原材料
39 35 主要材料
40 35 间辅材料
41 36 工资
42 36 福利
43 36 年奖金
现在需求是:我想查询itemid=2,也就是管理费用和其下属所有节点的信息
通过cte可以很简单达到需求要的数据
为了体现cte的方便性,我特意也写了一个sql2000版本的解决方法,先看看sql2000是怎么解决这个问题的
代码如下:
--sql2000版本
declare @i int
select @i=2;
/*
使用临时表作为堆栈来跟踪所有正在处理中的项目(已经开始但尚未结束)。
某个项目一旦处理完毕,将被从堆栈中删除。
当发现新的项目时,这些项目将被添加到堆栈中。
*/
create table #tem(
[itemid] [int] not null,
[level] int
);
/*
存放结果
*/
create table #list(
[itemid] [int] not null,
[parentitemid] [int] not null default ((0)),
[itemname] [nvarchar](100) not null default (''),
[level] int
);
insert into #tem([itemid],[level])
select itemid, 1
from co_itemnameset
where itemid=@i
insert into #list([itemid],[parentitemid],[itemname],[level])
select itemid, parentitemid, itemname ,1
from co_itemnameset
where itemid=@i
declare @level int
select @level=1
declare @current int
select @current=0
/*
当 @level 大于 0 时,执行以下步骤:
1.如果当前级别 (@level) 的堆栈中有项目,就选择其中一个,并称之为 @current。
2.从堆栈中删除该项目以免重复处理它,然后将其所有子项目添加到堆栈的下一级 (@level + 1) 中。
3.如果有子项目 (if @@rowcount > 0),则下降一级处理它们 (@level = @level + 1);否则,继续在当前级别上处理。
4.最后,如果在当前级别的堆栈中没有待处理的项目,则返回到上一级,看上一级是否有待处理的项目 (@level = @level - 1)。当再没有上一级时,则完毕。
*/
while(@level>0)
begin
select @current=itemid
from #tem
where [level]=@level
if @@rowcount>0
begin
--从堆栈中删除该项目以免重复处理它
delete from #tem
where [level]=@level and itemid=@current
--将其所有子项目添加到堆栈的下一级 (@level + 1) 中。
insert into #tem([itemid],[level])
select [itemid],@level+1
from co_itemnameset
where parentitemid=@current
--将其所有子项目添加
insert into #list([itemid],[parentitemid],[itemname],[level])
select [itemid],[parentitemid],[itemname] ,@level+1
from co_itemnameset
where parentitemid=@current
if @@rowcount>0
begin
select @level=@level+1
end
end
else
begin
select @level=@level-1
end
end
--显示结果
select * from #list
drop table #tem
drop table #list
go
结果如下:
itemid parentitemid itemname level
2 0 管理费用 1
52 2 汽车费用 2
55 2 招聘费 2
56 2 排污费 2
53 52 燃料 3
54 52 轮胎 3
大家看到sql2000解决这个问题比较麻烦,要实现这需求编写的代码比较多,比较复杂
现在好了,在sql2005中通过cte的递归特点可以2步就实现.
得到同样的结果,sql2005的cte代码简单了许多.这就是cte支持递归查询的魅力。
请看下面的代码:
代码如下:
--sql2005版本
declare @i int
select @i=2;
with co_itemnameset_cte(itemid, parentitemid, itemname,level)
as
(
select itemid, parentitemid, itemname ,1 as [level]
from co_itemnameset
where itemid=@i
union all
select c.itemid, c.parentitemid, c.itemname ,[level] + 1
from co_itemnameset c inner join co_itemnameset_cte ct
on c.parentitemid=ct.itemid
)
select * from co_itemnameset_cte
go
其它类似信息

推荐信息