2016-09-10 41 views
1

我需要按層次順序列出我的數據庫(PostgreSQL)的所有表。 這意味着:如果表「用戶」具有表「角色」的外鍵,則它必須在列表中的「角色」之後。在以PostgreSQL - 所有表的分層列表

等價的東西:

EXEC sp_msdependencies @intrans = 1 

在SQL Server。

我試過,但沒有成功:

SELECT 
    pt.table_name as tablename, 
    string_agg(DISTINCT ccu.table_name, ',') AS reftable 
FROM information_schema.tables pt 
LEFT JOIN information_schema.columns c 
    ON c.table_name = pt.table_name 
LEFT JOIN information_schema.table_constraints tc 
    ON tc.table_name = pt.table_name AND tc.constraint_type = 'FOREIGN KEY' 
LEFT JOIN information_schema.key_column_usage AS kcu 
    ON tc.constraint_name = kcu.constraint_name AND kcu.column_name = c.column_name 
LEFT JOIN information_schema.constraint_column_usage AS ccu 
    ON ccu.constraint_name = tc.constraint_name 
WHERE pt.table_schema = 'public' 
GROUP BY pt.table_name,pt.table_type 
ORDER BY pt.table_type DESC, COUNT(TRUE) ASC; 

回答

1

我不認爲你可以用一個簡單的SELECT做到這一點。您可能需要遞歸查詢。

information_schemainformation_schema似乎特別不適合這種情況,因爲它假定約束名稱在模式內是唯一的,這是Postgres未強制執行的。換句話說,如果你有兩個同名的約束條件,我不認爲有任何方法可以在constraint_column_usage中區分它們。所以你最好使用Postgres自己的目錄。

這似乎工作,雖然我還沒有徹底測試它:

WITH RECURSIVE ref (tbl, reftbl, depth) AS (
    SELECT pg_class.oid, NULL::oid, 0 
    FROM pg_class 
    JOIN pg_namespace ON 
    pg_namespace.oid = pg_class.relnamespace 
    WHERE 
    relkind = 'r' AND 
    nspname = 'public' AND 
    NOT EXISTS (
     SELECT 1 FROM pg_constraint 
     WHERE 
     conrelid = pg_class.oid AND 
     contype = 'f' 
    ) 
    UNION ALL 
    SELECT conrelid, ref.tbl, ref.depth + 1 
    FROM ref 
    JOIN pg_constraint ON 
    confrelid = ref.tbl AND 
    contype = 'f' 
) 
SELECT 
    tbl::regclass::text as tablename, 
    string_agg(DISTINCT reftbl::regclass::text, ',') as reftables 
FROM ref 
GROUP BY tablename 
ORDER BY max(depth) 
+0

嗯,謝謝您的回答。但是,您的示例不會返回任何內容,只是始終「查詢正在運行」而沒有結束。 :D –

+2

@Marcelo:你有循環引用嗎?如果是這樣,沒有辦法訂購它們。 –