2012-08-27 5 views

Trả lời

8

Vì bạn đang sử dụng phiên bản cũ của PostgreSQL, bạn có thể phải sử dụng hàm PL/PgSQL để xử lý độ sâu thừa kế của> 1. Trên PostgreSQL hiện đại (hoặc thậm chí 8.4), bạn sẽ sử dụng một đệ quy phổ biến biểu thức bảng (WITH RECURSIVE).

Bảng pg_catalog.pg_inherits là chìa khóa. Đưa ra:

create table pp();  -- The parent we'll search for 
CREATE TABLE notpp(); -- Another root for multiple inheritance 
create table cc() inherits (pp); -- a 1st level child of pp 
create table dd() inherits (cc,notpp); -- a 2nd level child of pp that also inherits aa 
create table notshown() inherits (notpp); -- Table that inherits only notpp 
create table ccdd() inherits (cc,dd) -- Inheritance is a graph not a tree; join node 

Một kết quả chính xác sẽ tìm cc, dd, và ccdd, nhưng không tìm thấy notpp hoặc notshown.

Một truy vấn duy nhất chuyên sâu là:

SELECT pg_namespace.nspname, pg_class.relname 
FROM pg_catalog.pg_inherits 
    INNER JOIN pg_catalog.pg_class ON (pg_inherits.inhrelid = pg_class.oid) 
    INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid) 
WHERE inhparent = 'pp'::regclass; 

... nhưng điều này sẽ chỉ tìm thấy cc.

Đối với đa sâu thừa kế (tức là tableC thừa hưởng tableB thừa hưởng tableA), bạn cần phải mở rộng đó thông qua một CTE đệ quy hoặc một vòng lặp trong PL/pgSQL, sử dụng trẻ em trong những vòng cuối cùng với bố mẹ ở bên cạnh.

Cập nhật: Đây là phiên bản tương thích 8.3 nên đệ quy tìm tất cả các bảng kế thừa trực tiếp hoặc gián tiếp từ cha mẹ đã cho. Nếu sử dụng nhiều thừa kế, nó sẽ tìm thấy bất kỳ bảng nào có bảng mục tiêu là một trong các bảng cha của nó ở bất kỳ điểm nào dọc theo cây.

CREATE OR REPLACE FUNCTION find_children(oid) RETURNS SETOF oid as $$ 
SELECT i.inhrelid FROM pg_catalog.pg_inherits i WHERE i.inhparent = $1 
UNION 
SELECT find_children(i.inhrelid) FROM pg_catalog.pg_inherits i WHERE i.inhparent = $1; 
$$ LANGUAGE 'sql' STABLE; 

CREATE OR REPLACE FUNCTION find_children_of(parentoid IN regclass, schemaname OUT name, tablename OUT name) RETURNS SETOF record AS $$ 
SELECT pg_namespace.nspname, pg_class.relname 
     FROM find_children($1) inh(inhrelid) 
      INNER JOIN pg_catalog.pg_class ON (inh.inhrelid = pg_class.oid) 
      INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid); 
$$ LANGUAGE 'sql' STABLE; 

Cách sử dụng:

regress=# SELECT * FROM find_children_of('pp'::regclass); 
schemaname | tablename 
------------+----------- 
public  | cc 
public  | dd 
public  | ccdd 
(3 rows) 

Dưới đây là phiên bản CTE đệ quy, trong đó sẽ có tác dụng nếu bạn cập nhật Thạc, nhưng sẽ không hoạt động trên phiên bản hiện tại của bạn. Đó là IMO sạch hơn nhiều.

WITH RECURSIVE inh AS (
     SELECT i.inhrelid FROM pg_catalog.pg_inherits i WHERE inhparent = 'pp'::regclass 
     UNION 
     SELECT i.inhrelid FROM inh INNER JOIN pg_catalog.pg_inherits i ON (inh.inhrelid = i.inhparent) 
) 
SELECT pg_namespace.nspname, pg_class.relname 
    FROM inh 
     INNER JOIN pg_catalog.pg_class ON (inh.inhrelid = pg_class.oid) 
     INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid); 
+1

+1 để đề cập đến nhiều thừa kế. Tôi không nghĩ về điều đó. –

+0

Đây là truy vấn tuyệt vời. Tôi chỉ cố gắng thực hiện nó và nó làm việc hoàn hảo !! Tôi đã sửa đổi điều này để phù hợp với quy ước đặt tên của chúng tôi. Cảm ơn rất nhiều vì điều này ... – Arun

+0

@Arun Vui vì nó đã giúp. –

2

Các tuyên bố sau lấy tất cả các bảng con của bảng public.base_table_name:

select bt.relname as table_name, bns.nspname as table_schema 
from pg_class ct 
    join pg_namespace cns on ct.relnamespace = cns.oid and cns.nspname = 'public' 
    join pg_inherits i on i.inhparent = ct.oid and ct.relname = 'base_table_name' 
    join pg_class bt on i.inhrelid = bt.oid 
    join pg_namespace bns on bt.relnamespace = bns.oid 

Nó sẽ làm việc với 8.3 mặc dù tôi không chắc chắn 100%.

+0

Làm việc như một sự quyến rũ !!! Rất cám ơn vì điều này. – Arun

+0

@CraigRinger, Cảm ơn bạn đã nhập, bạn có thể vui lòng cho tôi biết nếu có thể tìm thấy trẻ em nếu thừa kế đa cấp ở đó không? – Arun

1

Đối với những người đang chạy phiên bản PostgreSQL với hỗ trợ RECURSIVE đây là hàm tìm các bảng có nguồn gốc cho bảng cơ sở được chỉ định.

CREATE OR REPLACE FUNCTION tables_derived_from(base_namespace name, base_table name) 
RETURNS TABLE (table_schema name, table_name name, oid oid) 
AS $BODY$ 
    WITH RECURSIVE inherited_id AS 
    (
     SELECT i.inhrelid AS oid 
     FROM pg_inherits i 
     JOIN pg_class base_t ON i.inhparent = base_t.oid 
     JOIN pg_namespace base_ns ON base_t.relnamespace = base_ns.oid 
     WHERE base_ns.nspname = base_namespace AND base_t.relname = base_table 

     UNION 

     SELECT i.inhrelid AS oid 
     FROM pg_inherits i 
     JOIN inherited_id b ON i.inhparent = b.oid 
    ) 
    SELECT child_ns.nspname as table_schema, child_t.relname as table_name, child_t.oid 
    FROM inherited_id i 
    JOIN pg_class child_t ON i.oid = child_t.oid 
    JOIN pg_namespace child_ns ON child_t.relnamespace = child_ns.oid 
    ORDER BY 1, 2, 3; 
$BODY$ LANGUAGE sql STABLE; 
1

Điều quan trọng cần lưu ý là một bảng có thể kế thừa nhiều bảng, và không ai trong số các giải pháp được liệt kê thực sự phơi bày đó; họ chỉ cần đi bộ xuống cây của cha mẹ đơn thân. Xem xét:

CREATE TABLE a(); 
CREATE TABLE b(); 
CREATE TABLE ab_() INHERITS (a,b); 
CREATE TABLE ba_() INHERITS (b,a); 
CREATE TABLE ab__() INHERITS (ab_); 
CREATE TABLE ba__() INHERITS (ba_); 
CREATE TABLE ab_ba_() INHERITS (ab_, ba_); 
CREATE TABLE ba_ab_() INHERITS (ba_, ab_); 

WITH RECURSIVE inh AS (
     SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM pg_catalog.pg_inherits i WHERE inhparent = 'a'::regclass 
     UNION 
     SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM inh INNER JOIN pg_catalog.pg_inherits i ON (inh.inhrelid = i.inhparent) 
) SELECT * FROM inh; 
inhparent | inhrelid | inhseqno 
-----------+----------+---------- 
a   | ab_  |  1 
a   | ba_  |  2 
ab_  | ab__  |  1 
ba_  | ba__  |  1 
ab_  | ab_ba_ |  1 
ba_  | ab_ba_ |  2 
ba_  | ba_ab_ |  1 
ab_  | ba_ab_ |  2 
(8 rows) 

ý rằng b không hiển thị ở tất cả các đó là không chính xác, vì cả hai ab_ và ba_ kế thừa b.

Tôi nghi ngờ cách "tốt nhất" để xử lý này sẽ là một cột văn bản [] và chứa (mảng [inhparent :: regclass]) :: văn bản cho mỗi bảng. Điều đó sẽ cung cấp cho bạn một cái gì đó giống như

inhrelid path 
ab_  {"{a,b}"} 
ba_  {"{b,a}"} 
ab_ba_  {"{a,b}","{b,a}"} 

Mặc dù rõ ràng không lý tưởng, ít nhất cũng sẽ phơi bày đường dẫn thừa kế hoàn chỉnh và cho phép bạn truy cập nó với đủ thể dục. Thật không may, xây dựng mà không phải là ở tất cả các dễ dàng.

Cách thay thế hơi đơn giản hơn là không bao gồm đường dẫn thừa kế đầy đủ ở mỗi cấp, chỉ mỗi bảng trực tiếp cha mẹ. Điều đó sẽ cung cấp cho bạn điều này:

inhrelid parents 
ab_   {a,b} 
ba_   {b,a} 
ab_ba_  {ab_,ba_}