TL;DR
在此版本中,您无需人工读取值并自行输入。
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。
非交互式解决方案
只是添加到其他两个答案,对于我们这些需要通过非交互式脚本创建这些Sequences,同时修补实时数据库的人。
也就是说,当您不想手动 SELECT 值并自己将其键入到后续的 CREATE 语句中时。
简而言之,您可以不这样做:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
...因为CREATE SEQUENCE 中的START [WITH] 子句需要一个值,而不是子查询。
注意:根据经验,这适用于所有非 CRUD(ie:除INSERT、SELECT、UPDATE、DELETE)之外的任何语句strong>pgSQL AFAIK。
但是,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 将准确返回指定的值,序列推进从以下nextval 开始。
——来自this entry in the documentation
在不相关的注释中,您也可以直接使用CREATE 指定拥有Sequence 的列,以后不必更改它:
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;
像这样使用它:
INSERT INTO foo (data) VALUES ('asdf');
-- ERROR: null value in column "a" violates not-null constraint
SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
-- OK: 1 row(s) affected