web-dev-qa-db-ja.com

シーケンスがPostgres(plpgsql)に存在するかどうかを確認します

ストアドプロシージャ内で、シーケンスが既に存在するかどうかをテストしようとしています。

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

上記のスニペットのいくつかのバリエーションを運なしで試しました。トピックについて何も見つけられないように見えるので、Googleに間違った条件を与えているに違いありません。どんな助けでもありがたいです!

23
Ilia Choly

Pg_classテーブルをクエリして、relnameが存在するかどうかを確認できます。

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

@rfuscaからの回答は、名前がシーケンスに対してのみ有効であると確信している場合(つまり、通常のテーブル、インデックス、ビュー、複合型、TOASTテーブル、または外部テーブル)、および複数のスキーマについて心配する必要はありません。つまり、ほとんどの一般的なケースで機能しますが、完全に厳密というわけではありません。

その名前のsequenceが特定のschemaに存在するかどうかをテストする場合、これは機能するはずです。

-- 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;
18
kgrittn

更新: to_regclass() Postgres 9.4を使用することで、存在を簡単にテストできるようになりました。

_SELECT to_regclass('schema_name.table_name');
_

しかし、詳細を読んでください:

完全な機能

シーケンスだけでなく、名前と競合するanyテーブルのようなオブジェクトをチェックする必要があります。

この関数は、名前が使用可能な場合に新しいシーケンスを作成し、他の場合はそれぞれ意味のある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インジェクションを防ぎます。詳細:

  • 2つの個別のパラメーターにより、現在の_search_path_とは関係なく、任意のスキーマでシーケンスを許可し、quote_ident()がその役割を実行できるようにします。 quote_ident()はスキーマ修飾名で失敗する-あいまいです。

  • Schemaパラメータにはデフォルト値があるため、呼び出しから省略できます。スキーマが指定されていない場合、関数はデフォルトで_current_schema_になります。 ドキュメントごと:

    _current_schema_は、検索パスの最初にあるスキーマの名前(または検索パスが空の場合はnull値)を返します。これは、ターゲットスキーマを指定せずに作成されたテーブルまたはその他の名前付きオブジェクトに使用されるスキーマです。

  • マニュアルの _pgclass.relkind_のタイプのリスト

  • PostgreSQLエラーコード

14

情報スキーマの使用はどうですか:

SELECT COUNT(*) 
FROM information_schema.sequences 
WHERE sequence_schema=? AND sequence_name=?
7
Dave Kok
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

このクエリは、スキーマ内のシーケンスの存在を確認できます。

1
xingang

シーケンスの存在を確認する必要がある実際の目的についてはわかりません。シーケンスが作成される前にシーケンスが存在するかどうかを確認することが目的である場合の代替、IF NOT EXISTS PostgreSQLの条件を使用できます。

CREATE SEQUENCE IF NOT EXISTS 'name'

を参照してくださいhttps://www.postgresql.org/docs/9.5/static/sql-createsequence.html

0
k_o_