给定复合类型的typname
,如何以递归方式找到所有组件类型的类型oids
?
示例:
CREATE TYPE t_station AS (x INT,
y INT,
label VARCHAR);
CREATE TYPE t_address AS (city VARCHAR,
street VARCHAR,
no INT,
stations t_station[]);
CREATE TYPE t_employee AS (name VARCHAR,
age INT,
coins INT[],
notes VARCHAR,
address t_address);
我可以获得oids
成员的t_employee
类型:
SELECT
t.typname, t.oid, a.attname, a.atttypid
FROM
pg_attribute a INNER JOIN pg_type t ON a.attrelid = t.typrelid
AND t.typname = 't_employee'
但是我需要对此进行说明,我想可以使用WITH RECURSIVE
:
WITH RECURSIVE allattrs(typname, oid, attname, atttypid) AS (
select t.typname, t.oid, a.attname, a.atttypid from pg_attribute a inner join pg_type t on a.attrelid = t.typrelid and t.typname = 't_employee'
union all
select z.* from
(select t.typname, t.oid, a.attname, a.atttypid from pg_attribute a inner join pg_type t on a.attrelid = t.typrelid) z,
allattrs y where y.atttypid = z.oid
)
SELECT * FROM allattrs limit 100
;
但是找不到t_station
复合类型的内部数组。
答案 0 :(得分:1)
数组类型会破坏您所遵循的简单链。如果是数组类型,则必须解析pg_type.typelem
以获取基类型。
WITH RECURSIVE cte(typname, type_oid, attname, atttypid, typelem) AS (
SELECT t.typname, t.oid, a.attname, a.atttypid, t.typelem
FROM pg_type t
LEFT JOIN pg_attribute a ON a.attrelid = t.typrelid
AND a.attnum > 0
AND NOT a.attisdropped
WHERE t.typrelid = 't_employee'::regclass
UNION ALL
SELECT t.typname, t.oid
,COALESCE(a.attname, t.typelem::regtype::text)
,COALESCE(a.atttypid, t.typelem), t.typelem
FROM cte c
JOIN pg_type t ON t.oid = c.atttypid AND (t.typtype = 'c' OR t.typelem > 0)
LEFT JOIN pg_attribute a ON a.attrelid = t.typrelid
AND a.attnum > 0
AND NOT a.attisdropped
)
SELECT typname, type_oid, attname, atttypid
FROM cte
WHERE typelem = 0 -- filter out rows for array types
如果要在结果中包含数组类型的额外行,请删除最终的WHERE条件..
此JOIN条件仅遵循复合类型或数组:
AND (t.typtype = 'c' OR t.typelem > 0)
我还添加了排除系统列和死列的条件:
AND a.attnum > 0
AND NOT a.attisdropped