【问题标题】:Find all composite type component types using WITH RECURSIVE使用 WITH RECURSIVE 查找所有复合类型组件类型
【发布时间】:2012-09-21 16:58:07
【问题描述】:

给定一个复合类型的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);

我可以得到t_employee的成员类型oids

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

【问题讨论】:

    标签: sql postgresql recursive-cte


    【解决方案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
    

    Details about catalog tables in the manual.

    【讨论】:

    • 啊,太好了!正是我需要的。我刚开始使用递归 CTE,并且有一个学习曲线.. 但是 PG 功能真的很棒!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多