SQL 编程 / 检索多行 |
当您使用由程序逻辑补充的游标时,您可解决普通的 SQL 不可解决的问题。这些问题之一就是部件爆炸问题,有时称为材料单处理。此问题的核心是对象之间的递归关系;一个对象包含其他对象,其又包含其他对象。
通常以制造库存为例来说明该问题。例如,公司制造各种部件。有些部件是分立的,但有些是其他部件的组合。
图: 部件爆炸问题
int part_list[200]; boom(top_part) int top_part; { long this_part, child_part; int next_to_do = 0, next_free = 1; part_list[next_to_do] = top_part; EXEC SQL DECLARE part_scan CURSOR FOR SELECT child INTO child_part FROM contains WHERE parent = this_part; while(next_to_do < next_free) { this_part = part_list[next_to_do]; EXEC SQL OPEN part_scan; while(SQLCODE == 0) { EXEC SQL FETCH part_scan; if(SQLCODE == 0) { part_list[next_free] = child_part; next_free += 1; } } EXEC SQL CLOSE part_scan; next_to_do += 1; } return (next_free - 1); }
从技术上讲,contains 表的每一行都是有向无环图,或树,的头结点。该函数执行对该树的宽度优先搜索,树根是作为它的参数传递的部件编号。该函数使用名为 part_scan 的游标返回在 parent 列中带有特定的值的所有行。最内层的 while 循环打开 part_scan 游标,在选择集中访存每一行,并当已检索了每一组件的部件编号时,关闭该游标。
此函数解决部件爆炸问题的核心,但该函数不是完整的解决方案。例如,它不允许组件在树中出现多个级别。此外,实际的 contains 表还会有列 count,给出在每一 parent 中使用的 child 部件的计数。返回每一组件部件的总计数的程序要复杂得多。
之前描述的迭代方法不是解决部件爆炸问题的唯一方法。如果代的数目有固定的限制,则您可使用嵌套的外部自连接,以单个 SELECT 语句解决该问题。
SELECT a.parent, a.child, b.child, c.child, d.child FROM contains a OUTER (contains b, OUTER (contains c, outer contains d) ) WHERE a.parent = top_part_number AND a.child = b.parent AND b.child = c.parent AND c.child = d.parent
此 SELECT 语句为来源于指定为 top_part_number 的祖先的每一行返回一行。对于不存在的级别,返回 Null 值。(请使用指示符变量来检测它们。)要将此解决方案扩展到更多级别,请选择 contains 表的附加的嵌套外部连接。您还可修订此解决方案来返回每一级别上部件的数目的计数。