35

我尝试使用Check if sequence exists in Postgres (plpgsql) 中的代码。

如果序列不存在,则创建序列。运行此代码两次会导致异常:

序列...已经存在。

仅当序列不存在时如何创建序列?

如果序列不存在,则不应写入任何消息并且不应发生错误,因此我无法在此问题的另一个答案中使用存储过程,因为如果序列存在,它每次都会将消息写入日志文件。

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

6 回答 6

53

Postgres 9.5 或更高版本

IF NOT EXISTSCREATE SEQUENCE在 Postgres 9.5中添加。这就是现在的简单解决方案:

CREATE SEQUENCE IF NOT EXISTS myschema.myseq;

但是无论如何都要考虑过时答案的细节......
你知道serialIDENTITY列,对吧?

Postgres 9.4 或更高版本

序列与其他几个类似表的对象共享名称空间。手册:

序列名称必须 与同一架构中的任何其他序列、表、索引、视图或外部表的名称不同。

大胆强调我的。所以分三种情况:

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

根据手册中的对象类型(relkindpg_class

r = 普通表
i = 索引
S = 序列
v = 视图
m = 物化视图
c = 复合类型
t = TOAST 表
f = 外部表

有关的:

于 2012-12-06T22:42:12.297 回答
13

我走了一条不同的路线:只捕获异常:

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

这样做的一个好处是您不必担心当前的模式是什么。

于 2014-06-05T02:21:57.380 回答
10

如果您不需要保留可能存在的序列,您可以删除它然后重新创建它:

DROP SEQUENCE IF EXISTS id_seq;
CREATE SEQUENCE id_seq;
于 2015-09-15T19:59:40.670 回答
3

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>;
于 2016-04-19T03:44:48.533 回答
0

我有一个功能可以随时清理我的数据库应用程序中的所有表。它是动态构建的,但本质是删除每个表中的所有数据并重置序列。这是重置其中一个表的顺序的代码:

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。可能会改变信息的存储位置。

于 2012-12-07T14:53:45.940 回答
0

有关序列的信息可以从information_schema.sequences参考)检索

尝试这样的事情(未经测试):

...
IF not EXISTS (SELECT * FROM information_schema.sequences
    WHERE sequence_schema = 'firma1' AND sequence_name = 'myseq') THEN
...
于 2012-12-06T21:36:57.690 回答