Thumbnail: jekyll

    DB2的公共表达式(WITH语句)

on under jekyll
1 minute read

WITH AS公共表达式详解

VALUES 函数是给定的值来定义临时集合的,例如 VALUES(1,2).

WITH 函数是用查询的结果集来定义临时集合的,从这个角度来讲类似于视图,不过不是视图。

WITH TEST(NAME_TEST, BDAY_TEST) AS   
(   
SELECT NAME,BIRTHDAY FROM USER--语句1   
)   
SELECT NAME_TEST FROM TEST WHERE BDAY_TEST='1949-10-1';--语句2  

即将语句一的查询结果作为名为TEST的临时表,在语句二中使用,而且只在这一次查询中有效。注意:后边跟的语句只能是SELECT语句,而不能是UPDATE、DELETE等其他语句!!!!

在定义一个公共表表达式之后,就可以像使用其他表一样 SQL 语句中使用它。可以任意次地使用公共表表达式。甚至可以在之前创建的公共表表达式的基础上,再创建一个或多个公共表表达式。例如:

WITH TEST1(A,B) AS   
(   
SELECT A,B FROM TABLE1--语句1   
),
TEST2(C,D) AS
(
SELECT C,D FROM TABLE2--语句2
)
SELECT A FROM TEST1,TEST2 WHERE A=C;--语句3

关于递归查询

网上发现一段讲的不错,复制过来,链接如下: http://www.cppblog.com/prayer/archive/2010/05/18/115666.html

如何用WITH语句做递归查询。递归查询的一个典型的例子是对树状结构的表进行查询,考虑如下的情况:

论坛首页
–数据库开发
—-DB2
——DB2 文章1
——–DB2 文章1 的评论1
——–DB2 文章1 的评论2
——DB2 文章2
—-Oracle
–Java技术
论坛首页
–数据库开发
—-DB2
——DB2 文章1
——–DB2 文章1 的评论1
——–DB2 文章1 的评论2
——DB2 文章2
—-Oracle
–Java技术

以上是一个论坛的典型例子,下面我们新建一个表来存储以上信息。

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

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

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

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

WITH TEMP(PARENTID,ID,NAME) AS   
(   
SELECT PARENTID,ID,NAME FROM BBS WHERE NAME='DB2'---语句1   
UNION ALL---语句2   
SELECT B.PARENTID,B.ID,B.NAME FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---语句3   
)   
SELECT NAME FROM TEMP;---语句4  
WITH TEMP(PARENTID,ID,NAME) AS
(
SELECT PARENTID,ID,NAME FROM BBS WHERE NAME='DB2'---语句1
UNION ALL---语句2
SELECT B.PARENTID,B.ID,B.NAME FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---语句3
)
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

学习笔记, 数据库, DB2
comments powered by Disqus