web-dev-qa-db-ja.com

存在しない場合のシーケンスの作成方法

シーケンスがPostgres(plpgsql)に存在するかどうかを確認する のコードを使用しようとしました。

シーケンスが存在しない場合に作成します。このコードを2回実行すると、例外が発生します。

シーケンス...は既に存在します。

存在しない場合にのみシーケンスを作成するにはどうすればよいですか?

シーケンスが存在しない場合、メッセージは書き込まれず、エラーも発生しません。シーケンスが存在する場合、毎回メッセージがログファイルに書き込まれるため、この質問に対する他の回答でストアドプロシージャを使用できません。

do $$
begin

SET search_path = '';
IF not EXISTS (SELECT * FROM pg_class
             WHERE relkind = 'S'
               AND oid::regclass::text = 'firma1.' || quote_ident('myseq'))
  THEN

SET search_path = firma1,public;

create sequence myseq;

END IF;

SET search_path = firma1,public;

end$$;

select nextval('myseq')::int as nr;
23
Andrus

Postgres 9.5以降

IF NOT EXISTSがPostgres 9.5のCREATE SEQUENCE に追加されました。それが今の簡単な解決策です:

CREATE SEQUENCE IF NOT EXISTS myschema.myseq;

しかし、とにかく古い回答の詳細を検討してください...
そして、あなたはserial列について知っていますよね?


Postgres 9.4以前

シーケンスの名前は、シーケンスだけでなく、いくつかのタイプのオブジェクトの名前と競合します。 マニュアル:

シーケンス名は、同じスキーマ内の他のシーケンス、テーブル、インデックス、ビュー、または外部テーブルの名前とは異なる必要があります。

大胆な強調鉱山。
3つのケースがあります。

  1. 名前が存在しません。 ->シーケンスを作成します。
  2. 同じ名前のシーケンスが存在します。 ->何もしない?出力はありますか?ロギング?
  3. 同じ名前の他の競合するオブジェクトが存在します。 ->何かしますか?出力はありますか?ロギング?

これらのいずれかの場合に何をしたいかを指定する必要があります。 DOステートメントは次のようになります。

DO
$do$
DECLARE
   _kind "char";
BEGIN
   SELECT relkind
   FROM   pg_class
   WHERE  oid = 'myschema.myseq'::regclass  -- sequence name, optionally schema-qualified
   INTO  _kind;

   IF NOT FOUND THEN       -- name is free
      CREATE SEQUENCE myschema.myseq;
   ELSIF _kind = 'S' THEN  -- sequence exists
      -- do nothing?
   ELSE                    -- object name exists for different kind
      -- do something!
   END IF;
END
$do$;

マニュアルによると、pg_classのオブジェクトタイプ(relkind

r =通常のテーブル
i =インデックス
S =シーケンス
v =表示
m =マテリアライズドビュー
c =複合型
t = TOASTテーブル
f =外部テーブル

関連:

35

私は別のルートに行きました:例外をキャッチしてください:

DO
$$
BEGIN
        CREATE SEQUENCE myseq;
EXCEPTION WHEN duplicate_table THEN
        -- do nothing, it's already there
END
$$ LANGUAGE plpgsql;

これの1つの素晴らしい利点は、現在のスキーマが何であるかを気にする必要がないことです。

13
Joe Shaw

潜在的に存在するシーケンスを保持する必要がない場合は、それをドロップしてから再作成することができます。

DROP SEQUENCE IF EXISTS id_seq;
CREATE SEQUENCE id_seq;
10
Evan Siroky

PostgresにはCREATE SEQUENCE IF NOT EXISTSと、シーケンスを削除しただけでシーケンスを使用したテーブルにデフォルト値がある場合、エラーが発生する可能性があります。

エラー:他のオブジェクトがシーケンスに依存しているため、シーケンス(sequence_name)を削除できませんSQL状態:2BP01

私にとって、これは助けることができます:

ALTER TABLE <tablename> ALTER COLUMN id DROP DEFAULT;
DROP SEQUENCE IF EXISTS <sequence_name>;
CREATE sequence <sequence_name>;
2
Osify

データベースアプリケーションのすべてのテーブルをいつでもクリーンアップする機能があります。動的に構築されますが、本質は、各テーブルからすべてのデータを削除し、シーケンスをリセットすることです。これは、テーブルの1つのシーケンスをリセットするコードです。

perform relname from pg_statio_all_sequences where relname = 'privileges_id_seq';
if found then
  select setval ('privileges_id_seq',1, false) into i_result;
end if;

お役に立てれば、

ろく

私はpostgres 8.4を使用していますが、9.2を使用しているようです。情報が保存される場所に違いが生じる可能性があります。

0
Loek Bergman

シーケンスに関する情報はinformation_schema.sequencesから取得できます( 参照

次のようなものを試してください(試していない):

...
IF not EXISTS (SELECT * FROM information_schema.sequences
    WHERE sequence_schema = 'firma1' AND sequence_name = 'myseq') THEN
...
0
sierrasdetandil