Row Type of the Resulting Collection-Derived Table
If you do not specify a derived-column name, the behavior of the database server depends on the data types of the elements in the underlying collection.
Although a collection-derived table appears to contain columns of individual data types, these columns are, in fact, the fields of a ROW data type. The data type of the ROW type as well as the column name depend on several factors.
- If type is a ROW data type, and no derived-column list is specified, then the ROW type of the collection-derived table is type.
- If type is a ROW data type and a derived column list is specified, then the ROW type of the collection-derived table is an unnamed ROW type whose column data types are the same as those of type and whose column names are taken from the derived column list.
- If type is not a ROW data type, the ROW type of the collection-derived table is an unnamed ROW type that contains one column of type and whose name is specified in the derived column list. If no name is specified, the database server assigns an implementation-dependent name to the column.
CREATE ROW TYPE person (name CHAR(255), id INT); CREATE TABLE parents ( name CHAR(255), id INT, children LIST (person NOT NULL) ); CREATE TABLE parents2 ( name CHAR(255), id INT, children_ids LIST (INT NOT NULL) );
ROW Type | Explicit Derived- Column List | Resulting ROW Type of the Collection-Derived Table | Code Example |
---|---|---|---|
Yes | No | Type |
In this example, the ROW type of c_table is parents. |
Yes | Yes | Unnamed ROW type of which the column type is Type and the column name is the name in the derived-column list |
In this example, the ROW type of c_table is ROW(c_name CHAR(255), c_id INT). |
No | No | Unnamed ROW that contains one column of Type that is assigned an implementation-dependent name | In the following example, if you do not specify c_id, the database server assigns a name to the derived column. In this case, the ROW type of c_table is ROW(server_defined_name INT). |
No | Yes | Unnamed ROW type that contains one column of Type whose name is in the derived-column list |
Here the ROW type of c_table is ROW(c_id INT). |
CREATE TABLE wanted(person_id int); CREATE FUNCTION wanted_person_count (person_set SET(person NOT NULL)) RETURNS INT; RETURN( SELECT COUNT (*) FROM TABLE (person_set) c_table, wanted WHERE c_tabel.id = wanted.person_id); END FUNCTION;
-- Table of categories and child categories, -- allowing any number of levels of subcategories CREATE TABLE CategoryChild ( categoryId INTEGER, childCategoryId SMALLINT ); INSERT INTO CategoryChild VALUES (1, 2); INSERT INTO CategoryChild VALUES (1, 3); INSERT INTO CategoryChild VALUES (1, 4); INSERT INTO CategoryChild VALUES (2, 5); INSERT INTO CategoryChild VALUES (2, 6); INSERT INTO CategoryChild VALUES (5, 7); INSERT INTO CategoryChild VALUES (7, 8); INSERT INTO CategoryChild VALUES (7, 9); INSERT INTO CategoryChild VALUES (4, 10); -- "R" == ROW type CREATE ROW TYPE categoryLevelR ( categoryId INTEGER, level SMALLINT ); -- DROP FUNCTION categoryDescendants ( -- INTEGER, SMALLINT ); CREATE FUNCTION categoryDescendants ( pCategoryId INTEGER, pLevel SMALLINT DEFAULT 0 ) RETURNS MULTISET (categoryLevelR NOT NULL) -- "p" == Prefix for Parameter names -- "l" == Prefix for Local variable names DEFINE lCategoryId LIKE CategoryChild.categoryId; DEFINE lRetSet MULTISET (categoryLevelR NOT NULL); DEFINE lCatRow categoryLevelR; -- TRACE ON; -- Must initialize collection before inserting rows LET lRetSet = 'MULTISET{}' :: MULTISET (categoryLevelR NOT NULL);
FOREACH SELECT childCategoryId INTO lCategoryId FROM CategoryChild WHERE categoryId = pCategoryId; INSERT INTO TABLE (lRetSet) VALUES (ROW (lCategoryId, pLevel+1)::categoryLevelR); -- INSERT INTO TABLE (lRetSet); -- EXECUTE FUNCTION categoryDescendantsR ( lCategoryId, -- pLevel+1 ); -- Need to iterate over results and insert into SET. -- See the SQL Tutorial, pg. 10-52: -- "Tip: You can only insert one value at a time -- into a simple collection." FOREACH EXECUTE FUNCTION categoryDescendantsR ( lCategoryId, pLevel+1 ) INTO lCatRow; INSERT INTO TABLE (lRetSet) VALUES (lCatRow); END FOREACH; END FOREACH; RETURN lRetSet; END FUNCTION ; -- "R" == recursive -- DROP FUNCTION categoryDescendantsR (INTEGER, SMALLINT); CREATE FUNCTION categoryDescendantsR ( pCategoryId INTEGER, pLevel SMALLINT DEFAULT 0 ) RETURNS categoryLevelR; DEFINE lCategoryId LIKE CategoryChild.categoryId; DEFINE lCatRow categoryLevelR; FOREACH SELECT childCategoryId INTO lCategoryId FROM CategoryChild WHERE categoryId = pCategoryId RETURN ROW (lCategoryId, pLevel+1)::categoryLevelR WITH RESUME; FOREACH EXECUTE FUNCTION categoryDescendantsR ( lCategoryId, pLevel+1 ) INTO lCatRow RETURN lCatRow WITH RESUME; END FOREACH; END FOREACH; END FUNCTION; -- Test the functions: SELECT lev, col FROM TABLE (( categoryDescendants (1, 0) )) AS CD (col, lev);