TL; DR
Đây là một phiên bản mà bạn không cần con người đọc giá trị và tự đánh ra giá trị đó.
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');
Một lựa chọn khác là sử dụng phần có thể tái sử dụng Function
được chia sẻ ở cuối câu trả lời này.
Một giải pháp không tương tác
Chỉ thêm vào hai câu trả lời còn lại, đối với những người trong chúng ta, những người cần Sequence
tạo các câu trả lời này bằng một tập lệnh không tương tác , trong khi vá một DB trực tiếp chẳng hạn.
Đó là, khi bạn không muốn SELECT
giá trị theo cách thủ công và tự nhập giá trị đó vào một CREATE
câu lệnh tiếp theo .
Trong ngắn hạn, bạn không thể làm:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
... vì START [WITH]
mệnh đề trong CREATE SEQUENCE
mong đợi một giá trị , không phải một truy vấn con.
Lưu ý: Theo nguyên tắc của ngón tay cái, áp dụng cho tất cả các phi CRUD ( ví dụ : bất cứ điều gì khác hơn INSERT
, SELECT
, UPDATE
, DELETE
) báo cáo trong pgSQL AFAIK.
Tuy nhiên, setval()
không! Do đó, những điều sau đây hoàn toàn ổn:
SELECT setval('foo_a_seq', max(a)) FROM foo;
Nếu không có dữ liệu và bạn không (muốn) biết về nó, hãy sử dụng coalesce()
để đặt giá trị mặc định:
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
-- ^ ^ ^
-- defaults to: 0
Tuy nhiên, việc đặt giá trị trình tự hiện tại 0
là khá vụng về, nếu không muốn nói là bất hợp pháp.
Sử dụng dạng ba tham số của setval
sẽ thích hợp hơn:
-- vvv
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
-- ^ ^
-- is_called
Việc đặt tham số thứ ba tùy chọn của setval
to false
sẽ ngăn tham số tiếp theo nextval
tiến trình tự trước khi trả về giá trị và do đó:
nextval
giá trị tiếp theo sẽ trả về chính xác giá trị được chỉ định và tiến trình trình tự bắt đầu với giá trị sau nextval
.
- từ mục này trong tài liệu
Trên một ghi chú không liên quan, bạn cũng có thể chỉ định cột sở hữu Sequence
trực tiếp với CREATE
, bạn không phải thay đổi nó sau này:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
Tóm tắt:
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');
Sử dụng một Function
Ngoài ra, nếu bạn định làm điều này cho nhiều cột, bạn có thể chọn sử dụng một cột thực 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;
Sử dụng nó như vậy:
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
SERIAL
giả hiện là kế thừa , được thay thế bằngGENERATED … AS IDENTITY
tính năng mới được xác định trong SQL: 2003 , trong Postgres 10 trở lên. Xem giải thích .