Subject | Recursive select statement |
---|---|
Author | Daniel L. Miller |
Post date | 2005-01-09T01:38:51Z |
Is there a way to write a recursive select statement without a
procedure? Given:
Table1
ID Data
1 All
2 Good
3 Programmers
4 Should
Table2
ID Master_ID Linked_ID
1 1 2
2 1 3
3 2 4
I would like to be able to return a result set from Table 1 listing all
the ID's and Data, starting from a given Data, that match any recursive
link listed in Table 2.
SELECT id, data FROM table1 WHERE data='All' or (recursive select).
I know I can do this with stored procedures, and a temporary table. Is
there another way? To further invite comment - my procedure method is
below:
To retrieve the result set, an example select would be:
SELECT id, data FROM get_related_data( 1, 5 )
The parameters to the function are the "root" id, and the level of
recursion desired.
scratch table defined as table TEMP_ID_SEARCH, fields TEMP_SEARCH_ID
integer and RESULT_ID integer, with a combined primary key.
CREATE PROCEDURE get_related_data (
target_id INTEGER,
relation_levels SMALLINT
)
RETURNS (
id INTEGER,
data VARCHAR(50)
)
AS
DECLARE VARIABLE search_id INTEGER;
BEGIN
/* Initialize search and store target in temporary list */
search_id = GEN_ID( g_temp_search_id, 1 );
INSERT INTO temp_id_search ( temp_search_id, result_id )
VALUES ( :search_id, :target_id );
/* Now add relations to temporary list */
EXECUTE PROCEDURE find_relations( :target_id, :relation_levels,
:search_id );
/* Now return the matching data entries */
FOR SELECT result_id FROM temp_id_search
WHERE temp_search_id = :search_id
INTO :target_id DO
FOR SELECT id, data FROM table1
WHERE id = :target_id
INTO :id, :data
DO SUSPEND;
/* Search complete, data returned, delete rows from temporary table */
DELETE FROM temp_id_search WHERE temp_search_id = :search_id;
END
CREATE PROCEDURE find_relations (
id INTEGER,
relation_level SMALLINT,
search_id INTEGER
)
AS
DECLARE VARIABLE related_id INTEGER;
BEGIN
WHILE ( relation_level > 1 ) DO BEGIN
FOR SELECT linked_id FROM table2
WHERE master_id = :id AND linked_id NOT IN
(SELECT result_id FROM temp_id_search WHERE temp_search_id =
:search_id)
INTO :related_id DO BEGIN
INSERT INTO temp_id_search ( temp_search_id, result_id )
VALUES ( :search_id, :related_id );
EXECUTE PROCEDURE find_relations( :related_id,
:relation_level, :search_id );
END
relation_level = relation_level - 1;
END
END
--
Daniel
procedure? Given:
Table1
ID Data
1 All
2 Good
3 Programmers
4 Should
Table2
ID Master_ID Linked_ID
1 1 2
2 1 3
3 2 4
I would like to be able to return a result set from Table 1 listing all
the ID's and Data, starting from a given Data, that match any recursive
link listed in Table 2.
SELECT id, data FROM table1 WHERE data='All' or (recursive select).
I know I can do this with stored procedures, and a temporary table. Is
there another way? To further invite comment - my procedure method is
below:
To retrieve the result set, an example select would be:
SELECT id, data FROM get_related_data( 1, 5 )
The parameters to the function are the "root" id, and the level of
recursion desired.
scratch table defined as table TEMP_ID_SEARCH, fields TEMP_SEARCH_ID
integer and RESULT_ID integer, with a combined primary key.
CREATE PROCEDURE get_related_data (
target_id INTEGER,
relation_levels SMALLINT
)
RETURNS (
id INTEGER,
data VARCHAR(50)
)
AS
DECLARE VARIABLE search_id INTEGER;
BEGIN
/* Initialize search and store target in temporary list */
search_id = GEN_ID( g_temp_search_id, 1 );
INSERT INTO temp_id_search ( temp_search_id, result_id )
VALUES ( :search_id, :target_id );
/* Now add relations to temporary list */
EXECUTE PROCEDURE find_relations( :target_id, :relation_levels,
:search_id );
/* Now return the matching data entries */
FOR SELECT result_id FROM temp_id_search
WHERE temp_search_id = :search_id
INTO :target_id DO
FOR SELECT id, data FROM table1
WHERE id = :target_id
INTO :id, :data
DO SUSPEND;
/* Search complete, data returned, delete rows from temporary table */
DELETE FROM temp_id_search WHERE temp_search_id = :search_id;
END
CREATE PROCEDURE find_relations (
id INTEGER,
relation_level SMALLINT,
search_id INTEGER
)
AS
DECLARE VARIABLE related_id INTEGER;
BEGIN
WHILE ( relation_level > 1 ) DO BEGIN
FOR SELECT linked_id FROM table2
WHERE master_id = :id AND linked_id NOT IN
(SELECT result_id FROM temp_id_search WHERE temp_search_id =
:search_id)
INTO :related_id DO BEGIN
INSERT INTO temp_id_search ( temp_search_id, result_id )
VALUES ( :search_id, :related_id );
EXECUTE PROCEDURE find_relations( :related_id,
:relation_level, :search_id );
END
relation_level = relation_level - 1;
END
END
--
Daniel