使用串行主键列安全地重命名表

时间:2013-02-01 15:33:05

标签: sql postgresql database-design ddl

我知道使用SERIAL主键的PostgreSQL表以PostgreSQL创建的隐式索引,序列和约束结束。问题是在重命名表时如何重命名这些隐式对象。下面是我尝试在最后通过具体问题解决这个问题。

给出如下表:

CREATE TABLE foo (
    pkey SERIAL PRIMARY KEY,
    value INTEGER
);

Postgres输出:

  

注意:CREATE TABLE将为串行列“foo.pkey”创建隐式序列“foo_pkey_seq”
  注意:CREATE TABLE / PRIMARY KEY将为表“foo”创建隐式索引“foo_pkey”
  查询成功返回,52毫秒没有结果。

pgAdmin III SQL窗格显示表的以下DDL脚本(已整理):

CREATE TABLE foo (
  pkey serial NOT NULL,
  value integer,
  CONSTRAINT foo_pkey PRIMARY KEY (pkey )
);
ALTER TABLE foo OWNER TO postgres;

现在重命名表:

ALTER table foo RENAME TO bar;
  

查询成功返回,17 ms没有结果。

pgAdmin III:

CREATE TABLE bar (
  pkey integer NOT NULL DEFAULT nextval('foo_pkey_seq'::regclass),
  value integer,
  CONSTRAINT foo_pkey PRIMARY KEY (pkey )
);
ALTER TABLE bar OWNER TO postgres;

请注意额外的 DEFAULT nextval('foo_pkey_seq'::regclass), ,这意味着重命名表不会重命名主键的序列,但现在我们明确nextval()

现在重命名序列:

我想保持数据库命名一致,所以我尝试了:

ALTER SEQUENCE foo_pkey_seq RENAME TO bar_pkey_seq;
  

查询成功返回,17 ms没有结果。

pgAdmin III:

CREATE TABLE bar (
  pkey serial NOT NULL,
  value integer,
  CONSTRAINT foo_pkey PRIMARY KEY (pkey )
);
ALTER TABLE bar OWNER TO postgres;

DEFAULT nextval('foo_pkey_seq'::regclass), 已消失。

问题

  1. 为什么DEFAULT nextval('foo_pkey_seq'::regclass)语句出现并消失?
  2. 有没有办法重命名表并同时重命名主键序列?
  3. 在客户端连接到数据库时重命名表然后顺序是否安全?是否存在并发问题?
  4. postgres如何知道使用哪个序列?是否有内部使用的数据库触发器?除了表格和序列之外还有什么可以重命名吗?
  5. 主键创建的隐式索引怎么样?这应该重命名吗?如果是这样,怎么办呢?
  6. 上面的约束名称怎么样?它仍然是foo_pkey。如何重命名约束?

1 个答案:

答案 0 :(得分:33)

serial不是实际的数据类型。 The manual states

  

数据类型smallserialserialbigserial不是真正的类型,   但仅仅是创建唯一标识符列的标记方便

解决伪数据类型的所有这些:

  • 创建名为tablename_colname_seq

  • 的序列
  • 分别为integer / int2创建int8(或smallserial / bigserial类型的列

  • 制作专栏NOT NULL DEFAULT nextval('tablename_colname_seq')

  • 使列拥有序列,以便自动将其删除

系统知道您是手动还是通过伪数据类型serial完成所有这些操作。 pgAdmin检查列出的功能,如果满足所有功能,则使用匹配的serial类型简化反向工程DDL脚本。如果不满足其中一个功能,则不会进行此简化。这是pgAdmin所做的事情。对于底层目录表,它们都是一样的。这样没有serial类型。

无法自动重命名已拥有的序列。你可以运行:

ALTER SEQUENCE ... RENAME TO ...
像你一样。系统本身并不关心名称。列DEFAULT存储OID'foo_pkey_seq'::regclass),您可以更改序列的名称而不会破坏 - OID保持不变。对于数据库中的外键和类似引用也是如此。

主键的隐式索引绑定到PK约束的名称,如果更改表的名称,将更改。 In Postgres 9.2 or later you can use

ALTER TABLE ... RENAME CONSTRAINT ..

也要纠正这一点。

也可以在引用表名时命名索引。 Similar procedure

ALTER INDEX .. RENAME TO  ..

您可以对表名进行各种非正式引用。系统无法强制重命名可以命名的对象。它并不关心。

当然,您不希望使引用这些名称的SQL代码无效。显然,您不希望在应用程序逻辑引用它们时更改名称。通常这对于索引,序列或约束的名称来说不是问题,因为这些名称通常不会被名称引用。

Postgres在重命名对象之前还获取对象的锁定。因此,如果有并发事务打开,对相关对象有任何锁定,则RENAME操作将停止,直到这些事务提交或回滚为止。

系统目录和OID

数据库架构存储在系统架构pg_catalog中的系统目录的表中。 All details in the manual here.如果您不确切知道自己在做什么,根本不应该弄乱这些表格。一个错误的举动,你可以打破你的数据库。 Use the DDL commands Postgres provides.

对于一些最重要的表格,Postgres提供object identifier types并输入类型转换来获取OID的名称,反之亦然。像:

SELECT 'foo_pkey_seq'::regclass

如果架构名称在search_path中且表名是唯一的,则表示与以下内容相同:

SELECT oid FROM pg_class WHERE relname = 'foo_pkey_seq';

大多数目录表的主键是oid,在内部,大多数引用都使用OID。