将“serial”添加到Postgres中的现有列

时间:2012-02-28 21:28:36

标签: postgresql

我的Postgres 9.0数据库中有一个小表(~30行),带有一个整数ID字段(主键),它当前包含从1开始的唯一顺序整数,但不是使用'serial'关键字创建的。

如何更改此表,以便从现在开始插入此表将使该字段的行为就像使用'serial'作为类型创建一样?

3 个答案:

答案 0 :(得分:102)

查看以下命令(尤其是注释块)。

DROP TABLE foo;
DROP TABLE bar;

CREATE TABLE foo (a int, b text);
CREATE TABLE bar (a serial, b text);

INSERT INTO foo (a, b) SELECT i, 'foo ' || i::text FROM generate_series(1, 5) i;
INSERT INTO bar (b) SELECT 'bar ' || i::text FROM generate_series(1, 5) i;

-- blocks of commands to turn foo into bar
CREATE SEQUENCE foo_a_seq;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
ALTER TABLE foo ALTER COLUMN a SET NOT NULL;
ALTER SEQUENCE foo_a_seq OWNED BY foo.a;    -- 8.2 or later

SELECT MAX(a) FROM foo;
SELECT setval('foo_a_seq', 5);  -- replace 5 by SELECT MAX result

INSERT INTO foo (b) VALUES('teste');
INSERT INTO bar (b) VALUES('teste');

SELECT * FROM foo;
SELECT * FROM bar;

答案 1 :(得分:36)

你也可以使用START WITH从特定点开始一个序列,虽然setval完成同样的事情,就像欧拉的回答一样,例如,

SELECT MAX(a) + 1 FROM foo;
CREATE SEQUENCE foo_a_seq START WITH 12345; -- replace 12345 with max above
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');

答案 2 :(得分:19)

非交互式解决方案

只需添加其他两个答案,对于我们这些需要由非交互式脚本创建这些Sequence的人,同时修补实时数据库

也就是说,当您不想手动SELECT值并将其自己输入后续CREATE语句时。

简而言之,您可以执行:

CREATE SEQUENCE foo_a_seq
    START WITH ( SELECT max(a) + 1 FROM foo);

...因为START [WITH]中的CREATE SEQUENCE子句需要,而不是子查询。

  

注意:根据经验,这适用于所有非CRUD(INSERTSELECTUPDATE以外的任何内容,{ {1}}) pgSQL AFAIK中的语句。

然而,DELETE确实如此!因此,以下是绝对正确的:

setval()

如果没有数据而您(不想)了解它,请使用SELECT setval('foo_a_seq', max(a)) FROM foo; 设置默认值:

coalesce()

但是,将当前序列值设置为SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo; -- ^ ^ ^ -- defaults to: 0 是笨拙的,如果不是非法的话 使用0的三参数形式会更合适:

setval

-- vvv SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo; -- ^ ^ -- is_called 的可选第三个参数设置为setval将阻止下一个false在返回值之前推进序列,因此:

  

下一个nextval将完全返回指定的值,并且序列推进从以下nextval开始。

- 来自this entry in the documentation

在不相关的说明中,您还可以直接使用nextval指定拥有Sequence的列,您不必在以后更改它:

CREATE

总结:

CREATE SEQUENCE foo_a_seq OWNED BY foo.a;

使用CREATE SEQUENCE foo_a_seq OWNED BY foo.a; SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo; ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');

或者,如果您计划对多个列执行此操作,则可以选择使用实际的Function

Function

像这样使用它:

CREATE OR REPLACE FUNCTION make_into_serial(table_name TEXT, column_name TEXT) RETURNS INTEGER AS $$
DECLARE
    start_with INTEGER;
    sequence_name TEXT;
BEGIN
    sequence_name := table_name || '_' || column_name || '_seq';
    EXECUTE 'SELECT coalesce(max(' || column_name || '), 0) + 1 FROM ' || table_name
            INTO start_with;
    EXECUTE 'CREATE SEQUENCE ' || sequence_name ||
            ' START WITH ' || start_with ||
            ' OWNED BY ' || table_name || '.' || column_name;
    EXECUTE 'ALTER TABLE ' || table_name || ' ALTER COLUMN ' || column_name ||
            ' SET DEFAULT nextVal(''' || sequence_name || ''')';
    RETURN start_with;
END;
$$ LANGUAGE plpgsql VOLATILE;