0

给定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复合类型的内部数组。

4

1 回答 1

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

手册中有关目录表的详细信息。

于 2012-09-21T21:34:55.040 回答