如果没有指定派生列名,那么数据库服务器的行为取决于基本集合元素的数据类型。
虽然集合派生表看起来包含单独的数据类型的列,但这些列实际上是 ROW 数据类型的字段。ROW 类型的数据类型和列名取决于几个元素。
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 类型 | 显式派生列列表 | 集合派生表产生的 ROW 类型 | 代码示例 |
---|---|---|---|
是 | 否 | Type |
SELECT (SELECT c_table.name FROM TABLE(parents.children) c_table WHERE c_table.id = 1002) FROM parents WHERE parents.id = 1001; 在此示例中,c_table 的 ROW 类型是 parents。 |
是 | 是 | 未命名的 ROW 类型,它的列类型是 Type ,而列名是派生列的列表中的名称 |
SELECT (SELECT c_table.c_name FROM TABLE(parents.children) c_table(c._name, c_id) WHERE c_table.c_id = 1002) FROM parents WHERE parents.id = 1001; 在此示例中,c_table 的 ROW 类型是 ROW(c_name CHAR(255), c_id INT)。 |
No | No | 未命名的 ROW ,它包含一个已指定依实现而定的名称的 Type 列 | 在以下示例中,如果不指定 c_id,数据库服务器会为派生列指定一个名称。在这种情况下,表 c_table 的 ROW 类型是 ROW(server_defined_name INT)。 |
否 | 是 | 未命名的 ROW 类型,它包含一个 Type 列。列名在派生列的列表中 |
SELECT(SELECT c_table.c_id FROM TABLE(parents2.child_ids) c_table (c_id) WHERE c_table.c_id = 1002) FROM parents WHERE parents.id = 1001; 这里,c_table 的 ROW 类型是 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);