将"serial"添加到Postgres中的现有列

nic*_*ten 80 postgresql

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

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

小智 112

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

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

  • 您不应该在setval中设置“ MAX(a)+1”吗?`SELECT MAX(a)+1 FROM foo; SELECT setval('foo_a_seq',6);` (2认同)

Joh*_*ell 42

您也可以使用START WITH从特定点开始一个序列,尽管setval完成同样的事情,如Euler的答案,例如,

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


ccj*_*mne 23

非交互式解决方案

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

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

总之,你能不能做:

CREATE SEQUENCE foo_a_seq
    START WITH ( SELECT max(a) + 1 FROM foo);
Run Code Online (Sandbox Code Playgroud)

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

注:作为一个经验法则,适用于所有非CRUD(:比其他任何东西INSERT,SELECT,UPDATE,DELETE在报表)pgSQL的 AFAIK.

但是,setval()确实!因此,以下是绝对正常的:

SELECT setval('foo_a_seq', max(a)) FROM foo;
Run Code Online (Sandbox Code Playgroud)

如果没有数据且您不想(想)了解它,请使用coalesce()设置默认值:

SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
--                         ^      ^         ^
--                       defaults to:       0
Run Code Online (Sandbox Code Playgroud)

在一个不相关的注释中,您还可以指定0直接拥有该列的列setval,您不必在以后更改它:

--                                             vvv
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
--                                                  ^   ^
--                                                is_called
Run Code Online (Sandbox Code Playgroud)

综上所述:

CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
Run Code Online (Sandbox Code Playgroud)

用一个 setval

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

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

像这样使用它:

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

  • 感谢@Amiko 的评论!`setval` 函数实际上只为序列设置当前“最新使用的值”。下一个 **available** 值(第一个实际使用的)将是一个!在空列上使用 `setval(...,coalesce(max(a), 1))` 会将其设置为以 `2`(下一个可用值)“开始”,如 [文档]( https://www.postgresql.org/docs/11/functions-sequence.html)。 (2认同)

M I*_*ama 9

PostgreSQL 10 及更高版本

不要使用serial. 感谢以上评论

ALTER TABLE mysmalltable
ALTER COLUMN id
ADD GENERATED BY DEFAULT AS IDENTITY;
Run Code Online (Sandbox Code Playgroud)


M. *_*put 5

为我工作PostgreSQL 12

它将我现有的 int 列转换为串行列。

CREATE SEQUENCE table_name_id_seq;
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT nextval('table_name_id_seq');
ALTER TABLE table_name ALTER COLUMN id SET NOT NULL;
ALTER SEQUENCE table_name_id_seq OWNED BY table_name.id;  
SELECT setval('table_name_id_seq', (SELECT max(id) FROM table_name));
Run Code Online (Sandbox Code Playgroud)