web-dev-qa-db-fra.com

Vérifier si la séquence existe dans Postgres (plpgsql)

J'essaie de tester, dans une procédure stockée, si une séquence existe déjà.

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

J'ai essayé plusieurs variantes de l'extrait ci-dessus sans succès. Je dois donner les mauvais termes à Google car je n'arrive pas à trouver quoi que ce soit sur le sujet. Toute aide est appréciée!

20
Ilia Choly

Vous devriez pouvoir interroger la table pg_class pour voir si le nom de fichier existe.

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

La réponse de @rfusca fonctionne si vous êtes certain que le nom ne peut être valide que pour une séquence (vous ne pouvez donc pas l'utiliser pour une table ordinaire, un index, une vue, un type composite, une table TOAST ou table étrangère), et vous n'êtes pas préoccupé par plusieurs schémas. En d'autres termes, cela fonctionne pour la plupart des cas courants, mais ce n'est pas tout à fait rigoureux.

Si vous voulez vérifier si un séquence portant ce nom existe dans un schéma particulier, cela devrait fonctionner:

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

Mise à jour: simplement tester l'existence est devenu plus simple avec to_regclass() dans Postgres 9.4 :

SELECT to_regclass('schema_name.table_name');

Mais lisez les détails:

Fonction complète

Vous devez vérifier si tout objet de typetable qui serait en conflit avec le nom, pas uniquement les séquences).

Cette fonction crée une nouvelle séquence si le nom est disponible et émet une valeur significative NOTICE/WARNING/EXCEPTION respectivement dans les autres cas:

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)';

Appel:

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

Ou:

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

Explique

  • Lisez également le commentaire sur la fonction à la fin du code.

  • Fonctionne dans Postgres 9.1+ . Pour les versions plus anciennes, il suffit de remplacer format() - qui protège contre l'injection SQL. Détails:

  • Deux paramètres distincts autorisent les séquences de tout schéma, indépendamment du search_path actuel, et permettent également à quote_ident() de faire son travail. quote_ident() échoue avec les noms qualifiés du schéma - serait ambigu.

  • Il existe une valeur par défaut pour le paramètre de schéma, vous pouvez donc l'omettre de l'appel. Si aucun schéma n'est donné, la fonction utilise par défaut le current_schema. Par documentation:

    current_schema renvoie le nom du schéma figurant en premier dans le chemin de recherche (ou une valeur nulle si le chemin de recherche est vide). Il s'agit du schéma Qui sera utilisé pour toutes les tables ou autres objets nommés créés Sans spécifier de schéma cible.

  • Liste des types pour pgclass.relkind dans le manuel .

  • Codes d'erreur PostgreSQL .

12
Erwin Brandstetter

Comment utiliser le schéma d'information:

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

Résultat:

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

Cette requête peut vérifier l'existence d'une séquence dans un schéma.

1
xingang

Je ne suis pas sûr de l’intention réelle pour laquelle la présence de la séquence doit être vérifiée. Une alternative si l'objectif est de vérifier si une séquence existe avant de la créer, la condition IF NOT EXISTS dans PostgreSQL peut être utilisée:

CREATE SEQUENCE IF NOT EXISTS 'name'

Voir https://www.postgresql.org/docs/9.5/static/sql-createsequence.html

0
k_o_