Non-interactive solution
Just adding to two other answers, for those of us who should have this Sequence created by a non-interactive script , when fixing, for example, a real-time DB.
That is, when you do not want the SELECT value manually and enter it yourself in the subsequent CREATE statement.
In short, you can not do this:
CREATE SEQUENCE foo_a_seq START WITH ( SELECT max(a) + 1 FROM foo);
... because the START [WITH] clause in CREATE SEQUENCE expects a value , not a subquery.
Note. Typically, this applies to all non-CRUD SELECTs (i.e.: nothing but INSERT , SELECT , UPDATE , DELETE ) in pgSQL AFAIK.
However, setval() does! Thus, it is absolutely true:
SELECT setval('foo_a_seq', max(a)) FROM foo;
If there is no data, and you do not know (want) about it, use coalesce() to set the default value:
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
In an unrelated note, you can also specify a column that owns Sequence directly from CREATE , you do not need to change it later:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
Eventually:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a; SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo; ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
Using Function
Alternatively, if you plan to do this for multiple columns, you can choose to use the actual 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;
Use it like this:
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