本博推荐文章快速导航: Sql Server2005 Transact-SQL 新兵器学习 MCAD学习 代码阅读总结 ASP.NET状态管理 DB(数据库) WAP WinForm Flex

Sql Server2005 Transact-SQL 新兵器学习总结之-公用表表达式(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最好用的地方是创建递归查询,下面演示一下这功能:
现有一数据结构如下:
QQ截图未命名1.bmp
这些数据存放在表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版本



结果如下:
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版本
posted @ 2008-07-31 14:52 aierong 阅读(1907) 评论(9)  编辑 收藏 网摘 所属分类: DB(数据库)Sql Server2005 Transact-SQL 新兵器学习总结

  回复  引用  查看    
#1楼 2008-07-31 15:24 | 姜敏      
其实你这种表结构在设计上个人认为有点不好.我的一种方法可以让你避免出现这种递归查询.
ItemId,ParentItemId,这两个字段在程序中构成了递归的原因,因为它们都是int形式的,(例如:一个"ItemId"等于1,那你很难想象出它的下一级分类的"ItemId"是多少,是2还是3还是?)
如果把这两个字段的表现形式改一下就非常直观了。
例如其中的一个一级目录的"ItemId"设成001,那它下面的子分类依次可以是:001001,001002,这样在查询大分类所有信息的时候就非常方便了。可以用like来匹配,like ’001%‘
不知道我说的LZ有没有明白呢。
  回复  引用  查看    
#2楼 2008-07-31 15:26 | 姜敏      
不过如果是针对已存在的数据库来说,LZ的方法还是相当不错的。值得学习。
  回复  引用  查看    
#3楼 [楼主]2008-07-31 15:33 | aierong      
谢谢你的提示

例如其中的一个一级目录的"ItemId"设成001,那它下面的子分类依次可以是:001001,001002,这样在查询大分类所有信息的时候就非常方便了。可以用like来匹配,like ’001%‘

这是一个好方法,你的意思是某个级别的id = 上级id+流水
那么ItemId字段的类型得修改为字符型,并要留足长度,应该级别不确定。
这样就可以不用递归来查询所有下级了
用like就解决
  回复  引用  查看    
#4楼 2008-07-31 15:41 | 姜敏      
嗯,就是这个解决方案,这只是我个人认为。方法不一定适用于每种环境。
  回复  引用  查看    
#5楼 [楼主]2008-07-31 15:52 | aierong      
我现在ItemId字段的值是随机产生的(identity)
我是插入简单,查询复杂

你那样做需要计算好ItemId的值,再插入
你是插入复杂点,查询简单

呵呵
  回复  引用  查看    
#6楼 2008-07-31 16:26 | PerfectDesign      
他还可以指定最大递归次数以防止递归黑洞
  回复  引用  查看    
#7楼 2008-07-31 22:16 | 木野狐(Neil Chen)      
@姜敏
这种办法有一些局限的。
比如编码位数,插入/修改等操作都复杂化。
好处是查询方便了。

  回复  引用  查看    
#8楼 2008-08-01 14:16 | airwolf2026      
莫非 WITH 就是CTE?
  回复  引用  查看    
#9楼 [楼主]2008-08-01 14:20 | aierong      
@airwolf2026
WITH 不是CTE
with是定义cte需要用到的关键字,具体怎么定义cte,请参考msdn


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-11-08 09:34 编辑过
Google站内搜索
[推荐职位]上海盛大网络招聘架构师



China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》


相关链接: