2012-08-10 227 views
18

我試圖在存儲過程中測試序列是否已存在。檢查Postgres中是否存在序列(plpgsql)

IF EXISTS SEQUENCE seq_name 
    RAISE EXCEPTION 'sequence % already exists!', seq_name 
END IF; 

我已經嘗試了上面代碼片段的幾個變種,但沒有運氣。我必須向Google提供錯誤的條款,因爲我似乎無法找到關於該主題的任何內容。任何幫助表示讚賞!

回答

17

您應該能夠查詢pg_class表以查看relname是否存在。

IF EXISTS (SELECT 0 FROM pg_class where relname = '<my sequence name here>') 
THEN 
    --stuff here 
END IF; 
16

如果你確定這個名字只能是有效的序列(即,你有信心,它不會對普通表,索引,視圖是使用從@rfusca答案的作品,複合類型,TOAST表或外部表),並且您不關心多個模式。換句話說,它適用於大多數常見的情況,但並不完全嚴格。

如果你想測試在一個特定的模式該名稱的序列是否存在,這應該工作:

-- Clear the search path so that the regclass of the sequence 
-- will be schema-qualified. 
SET search_path = ''; 
-- Do your conditional code. 
IF EXISTS (SELECT * FROM pg_class 
      WHERE relkind = 'S' 
       AND oid::regclass::text = 'public.' || quote_ident(seq_name)) 
    THEN 
    RAISE EXCEPTION 'sequence public.% already exists!', seq_name 
END IF; 
-- Restore the normal search path. 
RESET search_path; 
+0

什麼是OID :: regclass的文字::?同樣在我的情況下,relkind是「S」 - 大寫,但是對於表格 - 'r'小寫。 – Evgeny 2012-10-22 07:00:16

+0

另外經過測試,我發現quote_ident不適用於不存在的序列名稱。 – Evgeny 2012-10-22 07:15:49

+1

@Evgeny:關於轉換爲'regclass',然後轉換爲'text',請參閱本頁獲取有關'regclass'的信息http://www.postgresql.org/docs/9.2/interactive/datatype-oid.html - 'text'只是一個字符串。對不起,我把relkind的比較錯了 - 這確實是一個需要的資本S.將解決答案。我不明白你說的關於quote_ident的內容 - 這應該用於你傳入的參數;該名稱是否已經存在不會對quote_ident函數的行爲產生任何影響。 – kgrittn 2012-10-22 11:38:48

12

更新:簡單地生存測試已經在Postgres的變得更加簡單與to_regclass() 9.4

SELECT to_regclass('schema_name.table_name'); 

但讀的細節:

功能齊全

您需要檢查任何表狀物體,將與名稱,不僅僅是序列發生衝突。

這個函數創建一個新的序列,如果名稱是可用的和在其他情況下分別發出有意義的NOTICE/WARNING/EXCEPTION

CREATE OR REPLACE FUNCTION f_create_seq(_seq text, _schema text = NULL) 
    RETURNS void AS 
$func$ 
DECLARE 
    _fullname text := format('%I.%I', COALESCE(_schema,current_schema),_seq); 
    _relkind "char" := (SELECT c.relkind 
         FROM pg_namespace n 
         JOIN pg_class c ON c.relnamespace = n.oid 
         WHERE n.nspname = COALESCE(_schema, current_schema) 
         AND c.relname = _seq); 
BEGIN 
    IF _relkind IS NULL THEN -- name is free 
     EXECUTE 'CREATE SEQUENCE ' || _fullname; 
     RAISE NOTICE 'New sequence % created.', _fullname; 

    ELSIF _relkind = 'S' THEN -- 'S' = sequence 
     IF has_sequence_privilege(_fullname, 'USAGE') THEN 
     RAISE WARNING 'Sequence % already exists.', _fullname; 
     ELSE 
     RAISE EXCEPTION 
      'Sequence % already exists but you have no USAGE privilege.' 
     , _fullname; 
     END IF; 

    ELSE 
     RAISE EXCEPTION 'A(n) "%" named % already exists.' 
     -- Table-like objects in pg 9.4: 
     -- www.postgresql.org/docs/current/static/catalog-pg-class.html 
     , CASE _relkind WHEN 'r' THEN 'ordinary table' 
         WHEN 'i' THEN 'index' 
         -- WHEN 'S' THEN 'sequence' -- impossible here 
         WHEN 'v' THEN 'view' 
         WHEN 'm' THEN 'materialized view' 
         WHEN 'c' THEN 'composite type' 
         WHEN 't' THEN 'TOAST table' 
         WHEN 'f' THEN 'foreign table' 
         ELSE 'unknown object' END 
     , _fullname; 
    END IF; 
END 
$func$ LANGUAGE plpgsql; 

COMMENT ON FUNCTION f_create_seq(text, text) IS 
'Create sequence if name is free. 
RAISE NOTICE on successful creation. 
RAISE WARNING if it already exists. 
RAISE EXCEPTION if it already exists and current user lacks USAGE privilege. 
RAISE EXCEPTION if object of a different kind occupies the name. 
$1 _seq .. sequence name 
$2 _schema .. schema name (optional; default is CURRENT_SCHEMA)'; 

電話:

SELECT f_create_seq('myseq', 'myschema'); 

或者:

SELECT f_create_seq('myseq1'); -- defaults to current schema 

說明

  • 還在代碼的末尾讀取函數的註釋。

  • 在Postgres工作9.1+。對於較早的版本,您只需要替換format() - 防禦SQL注入。詳細信息:

  • 兩個獨立的參數,允許在任何架構序列獨立於當前search_path的,也允許quote_ident()來完成其工作。 quote_ident()不符合模式限定的名稱 - 將不明確。

  • 模式參數有一個默認值,所以您可以從調用中省略它。如果沒有給出模式,則該函數默認爲current_schemaPer documentation:

    current_schema返回是首先在 搜索路徑的模式(或者,如果搜索路徑是空的空值)的名稱。這是 架構,將用於任何表或其他命名對象,其中 創建時未指定目標架構。

  • pgclass.relkind in the manual的類型列表。

  • PostgreSQL error codes

1
select relname, relnamespace 
from pg_class join pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace 
where n.nspname='metastore_1' and relname='updater_state_id_seq'; 

結果:

 relname  | relnamespace 
------------------------------------- 
updater_state_id_seq |  32898 

這種查詢可以檢查一個模式內的序列的存在。

6

如何使用信息模式:

SELECT COUNT(*) 
FROM information_schema.sequences 
WHERE sequence_schema=? AND sequence_name=?