检查Postgres中是否存在序列(plpgsql)

Ili*_*oly 23 postgresql stored-procedures plpgsql

我试图在存储过程中测试序列是否已经存在.

IF EXISTS SEQUENCE seq_name
    RAISE EXCEPTION 'sequence % already exists!', seq_name
END IF;
Run Code Online (Sandbox Code Playgroud)

我已经尝试过几个不同的片段变形而没有运气.我必须向谷歌提供错误的条款,因为我似乎无法找到关于该主题的任何内容.任何帮助表示赞赏!

rfu*_*sca 22

您应该能够查询pg_class表以查看relname是否存在.

IF EXISTS (SELECT 0 FROM pg_class where relname = '<my sequence name here>' )
THEN
  --stuff here
END IF;
Run Code Online (Sandbox Code Playgroud)


kgr*_*ttn 18

@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;
Run Code Online (Sandbox Code Playgroud)

  • oid::regclass::text 是什么?同样在我的情况下 relkind 是“S” - 大写,但是对于表格 - 'r' 小写。 (2认同)
  • @Evgeny:关于转换为`regclass` 和`text`,请参阅此页面以了解有关`regclass` 的信息 http://www.postgresql.org/docs/9.2/interactive/datatype-oid.html -- ` text` 只是一个字符串。对不起,我把 relkind 比较弄错了——它确实是一个需要的大写 S。将修复答案。不过,我不明白您对quote_ident 的看法——它应该用于您传入的参数;该名称是否已经存在不会对 quote_ident 函数的行为产生任何影响。 (2认同)

Erw*_*ter 13

更新:to_regclass()在Postgres 9.4中,简单地测试存在变得更加简单:

SELECT to_regclass('schema_name.table_name');
Run Code Online (Sandbox Code Playgroud)

但阅读细节:

功能齐全

您需要检查任何与名称冲突的表格对象,而不仅仅是序列.

如果名称可用,此函数将创建一个新序列,并在其他情况下分别发出有意义的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)';
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT f_create_seq('myseq', 'myschema');
Run Code Online (Sandbox Code Playgroud)

要么:

SELECT f_create_seq('myseq1');  -- defaults to current schema
Run Code Online (Sandbox Code Playgroud)

说明

  • 另请阅读代码末尾的函数注释.

  • 适用于Postgres 9.1+.对于旧版本,您只需要替换format()- 这可以抵御SQL注入.细节:

  • 两个独立的参数允许任何模式中的序列独立于当前,search_path并且还允许quote_ident()执行其工作.quote_ident()失败的模式限定名称 - 将是模棱两可的.

  • schema参数有一个默认值,因此您可以从调用中省略它.如果没有给出模式,则函数默认为current_schema.每个文件:

    current_schema返回搜索路径中第一个模式的名称(如果搜索路径为空,则返回空值).这是将用于在未指定目标模式的情况下创建的任何表或其他命名对象的模式.

  • pgclass.relkind手册中的类型列表.

  • PostgreSQL错误代码.


Dav*_*Kok 7

如何使用信息架构:

SELECT COUNT(*) 
FROM information_schema.sequences 
WHERE sequence_schema=? AND sequence_name=?
Run Code Online (Sandbox Code Playgroud)