2012-09-21 3 views
0

복합 유형 typname이 주어지면 유형 oids을 재귀 적으로 찾으십니까??WITH RECURSIVE를 사용하여 모든 복합 유형 구성 요소 유형 찾기

예 :

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 
; 

하지만 내부 ar을 찾지 못했습니다. ray of t_station 복합 형.

답변

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 조건 마지막을 제거하려면 :

AND (t.typtype = 'c' OR t.typelem > 0) 

I을 또한 시스템 열과 고갈 된 열을 제외하는 조건을 추가했습니다.

AND a.attnum > 0 
AND NOT a.attisdropped 

Details about catalog tables in the manual.

+0

아, 멋지다! 정확히 내가 필요로하는 것. 방금 재귀 CTE를 사용하기 시작했고 거기에 학습 곡선이 있습니다. 그러나 PG의 기능은 정말 대단합니다! – oberstet