DB2 公共表表达式(WITH语句的使用)--分析

本文介绍了DB2中WITH语句(公共表表达式)的使用,通过一个BBS表的例子展示了如何查询DB2的所有文章及评论。通过递归查询,解释了WITH语句的工作原理,并提醒了避免死循环的关键点。同时,讨论了去掉WHERE子句可能产生的死循环情况,并提供了反向验证的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天看了一篇文章,讲的是DB2中with的使用,顺便学习分析了下,原文重点摘录如下:http://blog.youkuaiyun.com/shangboerds/article/details/4601023

  1. CREATE TABLE BBS  
  2. (  
  3. PARENTID INTEGER NOT NULL,  
  4. ID INTEGER NOT NULL,  
  5. NAME VARCHAR(200) NOT NULL---板块、文章、评论等。  
  6. );  
  7. insert into bbs (PARENTID,ID,NAME) values   
  8. (0,0,'论坛首页'),  
  9. (0,1,'数据库开发'),  
  10. (1,11,'DB2'),  
  11. (11,111,'DB2 文章1'),  
  12. (111,1111,'DB2 文章1 的评论1'),  
  13. (111,1112,'DB2 文章1 的评论2'),  
  14. (11,112,'DB2 文章2'),  
  15. (1,12,'Oracle'),  
  16. (0,2,'Java技术');  
 

现在万事兼备了,我们开始查询吧。假设现在让你查询一下‘DB2 文章1’的所有评论,有人说,这还不简单,如下这样就可以了。

  1. SELECT * FROM BBS WHERE PARENTID=(SELECT ID FROM BBS WHERE NAME='DB2');  
 

答案完全正确。那么,现在让你查询一下DB2的所有文章及评论,怎么办?传统的方法就很难查询了,这时候递归查询就派上用场了,如下:

  1. WITH TEMP(PARENTID,ID,NAME) AS  
  2. (  
  3. SELECT PARENTID,ID,NAME FROM BBS WHERE NAME='DB2'---语句1  
  4. UNION ALL---语句2  
  5. SELECT B.PARENTID,B.ID,B.NAME FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---语句3  
  6. )  
  7. SELECT NAME FROM TEMP;---语句4  
 

运行后,我们发现,结果完全正确,那它到底是怎么运行的呢?下面我们详细讲解一下。

1、首先,语句1将会执行,它只执行一次,作为循环的起点。得到结果集:DB2

2、接着,将循环执行语句3,这里我们有必要详细介绍一下。

首先语句3的意图是什么呢?说白了,它就是查找语句1产生结果集(DB2)的下一级,那么在目录树中DB2的下一级是什么呢?是‘DB2 文章1’和‘DB2 文章2’,并且把查询到的结果集作为下一次循环的起点,然后查询它们的下一级,直到没有下一级为止。

怎么样?还没明白?哈哈,不要紧,我们一步一步来:

首先,语句1产生结果集:DB2,作为循环的起点,把它和BBS表关联来查找它的下一级,查询后的结果为:‘DB2 文章1’和‘DB2 文章2’

接着,把上次的查询结果(也就是‘DB2 文章1’和‘DB2 文章2’)和BBS表关联来查找它们的下一级,查询后的结果为:‘DB2 文章1 的评论1’ 和 ‘DB2 文章1 的评论2’。

然后,在把上次的查询结果(也就是‘DB2 文章1 的评论1’ 和 ‘DB2 文章1 的评论2’)和BBS表关联来查找它们的下一级,此时,没有结果返回,循环结束

3、第三,将执行语句2,将所有的结果集放在一起,最终得到temp结果集。

4、最后,我们通过语句4 从temp临时集合中得到我们期望的查询结果。

怎么样,这回理解了吧,如果还没有理解,那么我也无能为力了。需要特别提醒的是

1、一定要注意语句3的关联条件,否则很容易就写成死循环了。

2、语句2必须是UNION ALL

最后请大家猜想一下,把语句1的where子句去掉,将会产生什么样的结果呢?

以上原文。

在文章最后提出把语句1的where子句去掉,会产生什么后果,应该会产生死循环。

原因是BBS表中第一条记录(0,0,’论坛首页‘)记录在他的父节点和子节点是一样的。

可以反向验证,将第一条记录去除,


WITH TEMP(PARENTID,ID,NA) AS
(
SELECT PARENTID,ID,NA FROM BBS WHERE na<>'论坛首页'---语句1
UNION ALL---语句2
SELECT B.PARENTID,B.ID,B.NA FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---语句3
)
SELECT NA FROM TEMP

则可正常使用

数据库开发        
 DB2          
 DB2 文章1      
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 
 DB2 文章2      
 Oracle       
 DB2          
 Oracle       
 DB2 文章1      
 DB2 文章2      
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 
 DB2 文章1      
 DB2 文章2      
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 

验证上文提出with处理的步骤,可以增加语句5
WITH TEMP(PARENTID,ID,NA) AS
(
SELECT PARENTID,ID,NA FROM BBS WHERE na='DB2'---语句1
UNION ALL---语句2
SELECT B.PARENTID,B.ID,B.NA FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---语句3
UNION ALL-
SELECT C.PARENTID,C.ID,C.NA FROM BBS AS C, TEMP AS T1 WHERE C.PARENTID=T1.ID---语句5

)
SELECT NA FROM TEMP

在with中加入了另一层循环,语句5

结果如下

DB2          
 DB2 文章1      
 DB2 文章2      
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 
 DB2 文章1      
 DB2 文章2      
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 
 DB2 文章1 的评论1 
 DB2 文章1 的评论2 

可以看到,with将语句1与语句3的结果集合并起来,传给语句5,至于最后

’DB2 文章1 的评论1 

 DB2 文章1 的评论2‘


1.11 衍生出两次 111.1111  ,111.1112

11.111 衍生出一次 111.1111 111.1112

则证明了,上文with处理步骤是正确的.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值