UNION ALL SELECT sub.deptid, sub.deptname, sub.superdept, super.level+1 FROM departments sub, temptab super WHERE sub.superdept = super.deptid ) SELECT deptname, level FROM temptab;
DEPTNAME LEVEL -------------------- -----------
Samples & Co. 1 Production 2 Sales 2 IT 2 QA 3 North 3 East 3 South 3 West 3 Manufacturing 3 Prebuilding 4 Finalbuilding 4
这意味着,结果集是一级一级地创建的。在本例中,这种差异或许算不了什么。但是在有些递归 SQL 的案例中,默认的排序次序则是至关重要的。例如,有一个包含讨论论坛的表:
CREATE TABLE discussion (postid INTEGER, superid INTEGER, title VARCHAR2(100), text VARCHAR2(1000) )
为了获得对所有讨论线索的了解,在 Oracle 中可以这样来查询这个表:
SELECT RPAD('', level-1, '--') || title FROM discussion CONNECT BY PRIOR superid = postid START WITH postid = 0;
1 -------------------------------------
Install Problem --Re: Install Problem ----Re: Install Problem ------Re: Install Problem --------Got it --General comment ----Re: General Comment Cannot find file --Re: Cannot find file ----Re: Cannot find file --Re: Cannot find file Help! Documentation missing!
在 DB2 中使用无格式(plain)递归 SQL 时,不能以这样的次序重新得到结果集。如果非要尝试这么做的话,将得到下面的结果:
WITH temptab(superid, postid, title, text, level) AS ( SELECT root.superid, root.postid, root.title, root.text, 1 FROM discussion root WHERE postid=0 UNION ALL SELECT sub.superid, sub.postid, sub.title, sub.text, super.level+1 FROM discussion sub, temptab super WHERE sub.superid = super.postid ) SELECT VARCHAR(REPEAT('--', level-1) || title , 60) FROM temptab;
1 ------------------------------------
Problem Discussions --Install Problem --Cannot find file --Help! Documentation missing! ----Re: Install Problem ----General comment ----Re: Cannot find file ----Re: Cannot find file ------Re: Install Problem ------Re: General Comment ------Re: Cannot find file --------Re: Install Problem ----------Got it
显然,对于用户来说该结果集完全没有用,因为这里失去了论坛上各个帖子之间的相关性。
在 DB2 UDB 中仿效 Oracle 的行为
在 DB2 中,要生成 Oracle 中那样的深度优先次序,解决方案的基础就是引入一个附加的伪列,这个伪列可以在 ORDER BY 属性中使用。这个列的类型是 VARCHAR,包含了到每个节点的路径,其格式为“1.3.1”。另外还引入了一个用户定义的表函数,这个函数可以返回一个给定节点的所有子节点。通过将子节点的序号连接到上级节点的路径上,能够可靠地维护伪列代码。可以使用 DB2 的 RANK() 函数来检索一个子节点的序号。之后,递归查询从这个函数中进行选择,并提供当前节点的 id 以及它的路径作为输入。
下面的例子将创建与上一例子中 Oracle 中的查询完全一致的结果集:
CREATE FUNCTION GetResponses(code VARCHAR(100), superid INTEGER) RETURNS TABLE(code VARCHAR(100), superid INTEGER, postid INTEGER, title VARCHAR(100), text VARCHAR(1000)) READS SQL DATA DETERMINISTIC NO EXTERNAL ACTION RETURN SELECT GetResponses.code || '.' || RTRIM(CHAR(RANK() OVER (ORDER BY postid))), T.superid , T.postid, T.title, T.text FROM discussion T WHERE T.superid = GetResponses.superid;
WITH TEMPTAB(code, superid, postid, title, text, level) AS ( VALUES(CAST('1' AS VARCHAR(100)), CAST(NULL AS INTEGER), 0, CAST(NULL AS VARCHAR(100)), CAST(NULL AS VARCHAR(1000)), 0) UNION ALL SELECT t.code, t.superid, t.postid, t.title, t.text, level+1 FROM TEMPTAB, TABLE(GetResponses(TEMPTAB.code, TEMPTAB.postid)) AS T ) SELECT VARCHAR(REPEAT('--', level-1) || title , 60) FROM TEMPTAB T WHERE t.superid is not null ORDER BY code;
1 -------------------------------------
Install Problem --Re: Install Problem ----Re: Install Problem ------Re: Install Problem --------Got it --General comment ----Re: General Comment Cannot find file --Re: Cannot find file ----Re: Cannot find file --Re: Cannot find file Help! Documentation missing!
为了使应用程序中的语句简单一些,这里同样可以将这些递归语句包装到一个 UDF 中。
一种更好地使用 DB2 Node 类型的方法
您必须清楚,基于一个字符串使用伪列以强制性地使结果集具有某一特定的次序,这只能保证总体上的层次结构次序。如果某个节点的直属子节点的数量超过 9 的话,这样做未必能够正确地对这些子节点排序。这是因为像“1.2.13”这样的字符串比“1.2.13”有着更低的次序。但是从语义上讲,事情刚好相反。如果您要依赖于这种方法,而又不能保证最多只有 9 个直属子节点,那么您就决不能为伪列使用一个字符串。
相反,您可以使用 DB2 Node 类型,这是一个 DB2 扩展,当前在 IBM DB2 Developer Domain 上(由 Jacques Roy 撰写的Using the Node Data Type to Solve Problems with Hierarchies in DB2 Universal Database )可以获得。您必须使用最低版本为 1.1 的 Node 类型扩展。可以通过 nodeVersion() 函数来检查版本。如果该函数不存在,那么就说明您使用的是更老版本的 DB2 Node 类型。
因此,现在我们不使用 VARCHAR 类型来维护伪列代码,而是使用用户定义类型的 Node。下面的例子对此作了演示。该例子将创建与上面使用 VARCHAR 的例子一样的结果集:
CREATE FUNCTION GetResponsesN(code Node, superid INTEGER) RETURNS TABLE(code Node, superid INTEGER, postid INTEGER, title VARCHAR(100), text VARCHAR(1000)) READS SQL DATA DETERMINISTIC NO EXTERNAL ACTION RETURN SELECT nodeInput(nodeOutput(GetResponsesN.code) || '.' || RTRIM(CHAR(RANK() OVER (ORDER BY postid)))), T.superid , T.postid, T.title, T.text FROM discussion T WHERE T.superid = GetResponsesN.superid;
WITH TEMPTAB(code, superid, postid, title, text, level) AS ( VALUES(nodeInput('1.1'), CAST(NULL AS INTEGER), 0, CAST(NULL AS VARCHAR(100)), CAST(NULL AS VARCHAR(1000)), 0) UNION ALL SELECT t.code, t.superid, t.postid, t.title, t.text, level+1 FROM TEMPTAB, TABLE(GetResponsesN(TEMPTAB.code, TEMPTAB.postid)) AS T ) SELECT VARCHAR(REPEAT('--', level-1) || title , 60) FROM TEMPTAB T WHERE t.superid is not null ORDER BY code;
1 -------------------------------------
Install Problem --Re: Install Problem ----Re: Install Problem ------Re: Install Problem --------Got it --General comment ----Re: General Comment Cannot find file --Re: Ca 上一页 [1] [2] [3] 下一页 |