2016-08-30 68 views
2

我有以下查詢,以觸發對架構公衆中的所有表:檢查觸發存在

SELECT 'CREATE TRIGGER ' || tab_name|| '_if_modified_trg INSERT OR UPDATE OR DELETE ON ' || tab_name|| ' FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ' AS trigger_creation_query 
FROM (
    SELECT quote_ident(table_schema) || '.' || quote_ident(table_name) as tab_name 
    FROM information_schema.tables 
    WHERE table_schema='public' 
    ) AS foo; 

而且我知道如何檢查是否觸發存在:

SELECT tgname 
from pg_trigger 
where not tgisinternal AND tgname='randomname' 

但我怎麼能檢查第一個查詢是否存在同名的觸發器 - 並跳過創建並繼續?這裏是我的解決方案,但它不工作:

SELECT 'CREATE TRIGGER ' || tab_name|| '_if_modified_trg INSERT OR UPDATE OR DELETE ON ' || tab_name|| ' FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ' AS trigger_creation_query 
FROM (
    SELECT quote_ident(table_schema) || '.' || quote_ident(table_name) as tab_name 
    FROM information_schema.tables 
    WHERE table_schema='public'  
) AS foo 
WHERE tab_name||'if_modified_trg' NOT IN (
    SELECT tgname 
    from pg_trigger 
    where not tgisinternal); 
+0

[如何檢查PostgreSQL中是否存在觸發器?](http://stackoverflow.com/q/33174638/1995738) – klin

回答

0

您可以使用DO語句或PLPGSQL函數來執行觸發器創造條件:

DO 
$do$ 
BEGIN 
    IF EXISTS (
     SELECT 1 
     FROM pg_trigger 
     WHERE NOT tgisinternal AND tgname = 'randomname' 
     ) THEN 
     -- do nothing 
    ELSE 
     -- create trigger 
    END IF; 
END 
$do$ 

在仔細檢查,其餘的代碼也有各種問題。 好像你正在試圖做到這一點:

DO 
$do$ 
DECLARE 
    _tbl regclass; 
    _trg text; 
BEGIN 
    FOR _tbl, _trg IN 
     SELECT c.oid::regclass, relname || '_if_modified_trg' 
     FROM pg_class c 
     JOIN pg_namespace n ON n.oid = c.relnamespace 
     WHERE n.nspname = 'public' 
     AND c.relkind = 'r' -- only regular tables 
    LOOP 
     IF EXISTS (
     SELECT 
     FROM pg_trigger 
     WHERE tgname = _trg 
     AND tgrelid = _tbl  -- check only for respective table 
     ) THEN 
     -- do nothing 
     ELSE 
     -- create trigger 
     EXECUTE format(
      'CREATE TRIGGER %I 
      BEFORE INSERT OR UPDATE OR DELETE ON %s 
      FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func()' 
      , _trg, _tbl::text 
     ); 
     END IF; 
    END LOOP; 
END 
$do$; 

我用的系統目錄pg_class而不是information_schema.tables多種原因。最重要的是,它包括表格的oid,這使得對pg_trigger的檢查更簡單並且更不容易出錯。

我們實際上可以進一步簡化並檢查在同一查詢中是否存在觸發器。大大加快,但是:

DO 
$do$ 
DECLARE 
    _tbl text; 
    _trg text; 
BEGIN 
FOR _tbl, _trg IN 
    SELECT c.oid::regclass::text, relname || '_if_modified_trg' 
    FROM pg_class  c 
    JOIN pg_namespace n ON n.oid = c.relnamespace 
    LEFT JOIN pg_trigger t ON t.tgname = c.relname || '_if_modified_trg' 
          AND t.tgrelid = c.oid -- check only respective table 
    WHERE n.nspname = 'public' 
    AND c.relkind = 'r' -- only regular tables 
    AND t.tgrelid IS NULL -- trigger does not exist yet 
LOOP 
    EXECUTE format(
     'CREATE TRIGGER %I 
     BEFORE INSERT OR UPDATE OR DELETE ON %s 
     FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func()' 
    , _trg_name, _tbl_oid::text 
    ); 
END LOOP; 
END 
$do$; 

相關答案與更多的解釋:

+0

@Avon:修正了一個錯誤:只通過常規表循環。 –

1

使用此您可以檢查是否觸發存在,如果不創建它。不要忘記最後的「;」。

DO $$ 
BEGIN 
    IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'randomname') THEN 
     CREATE TRIGGER randomname 
     AFTER INSERT OR UPDATE OR DELETE ON randomtable 
     FOR EACH ROW EXECUTE PROCEDURE randomfunction(); 
    END IF; 
END 
$$; 

我希望這可以幫助你。