Parts-explosion problem
When you use a cursor supplemented by program logic, you can solve problems that plain SQL cannot solve. One of these problems is the parts-explosion problem, sometimes called bill-of-materials processing. At the heart of this problem is a recursive relationship among objects; one object contains other objects, which contain yet others.
The problem is usually stated in terms of a manufacturing inventory. A company makes a variety of parts, for example. Some parts are discrete, but some are assemblages of other parts.
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);
}
Technically speaking, each row of the contains table is
the head node of a directed acyclic graph, or tree. The
function performs a breadth-first search of the tree whose root is
the part number passed as its parameter. The function uses a cursor
named part_scan to return all the rows with a particular value
in the parent column. The innermost while
loop
opens the part_scan cursor, fetches each row in the selection
set, and closes the cursor when the part number of each component
has been retrieved.
This function addresses the heart of the parts-explosion problem, but the function is not a complete solution. For example, it does not allow for components that appear at more than one level in the tree. Furthermore, a practical contains table would also have a column count, giving the count of child parts used in each parent. A program that returns a total count of each component part is much more complicated.
The iterative approach described previously is not the only way to approach the parts-explosion problem. If the number of generations has a fixed limit, you can solve the problem with a single SELECT statement using nested, outer self-joins.
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
This SELECT statement returns one row for each line of descent rooted in the part given as top_part_number. Null values are returned for levels that do not exist. (Use indicator variables to detect them.) To extend this solution to more levels, select additional nested outer joins of the contains table. You can also revise this solution to return counts of the number of parts at each level.