web-dev-qa-db-fra.com

Comment créer une séquence si elle n'existe pas

J'ai essayé d'utiliser le code de Vérifiez si la séquence existe dans Postgres (plpgsql) .

Pour créer une séquence si elle n'existe pas. L'exécution de ce code deux fois provoque une exception:

séquence ... existe déjà.

Comment créer une séquence uniquement si elle n'existe pas?

Si la séquence n'existe pas, aucun message ne doit être écrit et aucune erreur ne doit se produire, je ne peux donc pas utiliser la procédure stockée dans l'autre réponse à cette question car elle écrit un message dans le fichier journal à chaque fois si la séquence existe.

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 a été ajouté à CREATE SEQUENCE dans Postgres 9.5. Voilà la solution simple maintenant:

CREATE SEQUENCE IF NOT EXISTS myschema.myseq;

Mais considérez quand même les détails de la réponse obsolète ...
Et vous connaissez les colonnes serial, non?


Postgres 9.4 ou plus

Le nom d'une séquence est en conflit avec des noms d'objets de plusieurs types, pas seulement des séquences. Le manuel:

Le nom de séquence doit être distinct du nom de toute autre séquence , table, index, vue ou table étrangère dans le même schéma.

Accentuation mienne.
Vous avez donc trois cas:

  1. Le nom n'existe pas. > Créer une séquence.
  2. Il existe une séquence portant le même nom. > Ne rien faire? Une sortie? Toute journalisation?
  3. Il existe un autre objet en conflit portant le même nom. > Faire quelque chose? Une sortie? Toute journalisation?

Vous devez spécifier ce que vous voulez faire dans l'un ou l'autre de ces cas. L'instruction DO pourrait ressembler à ceci:

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$;

Types d'objets (relkind) dans pg_class selon le manuel :

r = table ordinaire
i = index
S = séquence
v = voir
m = vue matérialisée
c = type composite
t = table TOAST
f = table étrangère

En relation:

35
Erwin Brandstetter

J'ai emprunté une voie différente: il suffit de prendre l'exception:

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

Un avantage agréable à cela est que vous n'avez pas à vous soucier de votre schéma actuel.

13
Joe Shaw

Si vous n'avez pas besoin de conserver la séquence potentiellement existante, vous pouvez simplement la supprimer, puis la recréer:

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

Postgres n'a pas CREATE SEQUENCE IF NOT EXISTS et si la table a une valeur par défaut en utilisant la séquence si vous déposez simplement la séquence, vous pourriez obtenir une erreur:

ERREUR: impossible de supprimer la séquence (nom_séquence) car d'autres objets en dépendent État SQL: 2BP01

Pour moi, celui-ci peut aider:

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

J'ai une fonction pour nettoyer toutes les tables de mon application de base de données à tout moment. Il est construit dynamiquement, mais l'essentiel est qu'il supprime toutes les données de chaque table et réinitialise la séquence. Voici le code pour réinitialiser la séquence de l'une des tables:

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;

J'espère que cela t'aides,

Loek

J'utilise postgres 8.4, je vois que vous utilisez 9.2. Pourrait faire une différence où les informations sont stockées.

0
Loek Bergman

Les informations sur les séquences peuvent être récupérées à partir de information_schema.sequences ( référence )

Essayez quelque chose comme ça (non testé):

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