PostgreSQL Autoincrement
我正在从mysql切换到postgresql,我想知道如何实现自动增量值。我在PostgreSQL文档中看到了一个数据类型"serial",但在使用它时(在V8.0中)会出现语法错误。
是的,串行是等效功能。
1 2 3 4 5 6 7 8 9 10 11 | CREATE TABLE foo ( id SERIAL, bar VARCHAR); INSERT INTO foo (bar) VALUES ('blah'); INSERT INTO foo (bar) VALUES ('blah'); SELECT * FROM foo; 1,blah 2,blah |
序列只是围绕序列创建表时间宏。不能将序列号更改为现有列。
您可以使用任何其他整数数据类型,如
例子:
1 2 3 4 5 | CREATE SEQUENCE user_id_seq; CREATE TABLE USER ( user_id SMALLINT NOT NULL DEFAULT NEXTVAL('user_id_seq') ); ALTER SEQUENCE user_id_seq OWNED BY USER.user_id; |
最好使用自己的数据类型,而不是用户串行数据类型。
如果要将序列添加到表中已存在的ID中,可以使用:
1 2 | CREATE SEQUENCE user_id_seq; ALTER TABLE USER ALTER user_id SET DEFAULT NEXTVAL('user_id_seq'); |
虽然看起来序列相当于mysql auto_increment,但有一些细微但重要的区别:
1。失败的查询增加序列/序列对于失败的查询,序列列将递增。这会导致失败查询的碎片化,而不仅仅是行删除。例如,在PostgreSQL数据库上运行以下查询:
1 2 3 4 5 6 7 8 9 10 11 | CREATE TABLE table1 ( uid serial NOT NULL PRIMARY KEY, col_b INTEGER NOT NULL, CHECK (col_b>=0) ); INSERT INTO table1 (col_b) VALUES(1); INSERT INTO table1 (col_b) VALUES(-1); INSERT INTO table1 (col_b) VALUES(2); SELECT * FROM table1; |
您应该得到以下输出:
1 2 3 4 5 | uid | col_b -----+------- 1 | 1 3 | 2 (2 ROWS) |
注意uid是如何从1变为3而不是从1变为2的。
如果要手动创建自己的序列,并使用以下项,则仍然会发生这种情况:
1 2 3 4 5 6 7 | CREATE SEQUENCE table1_seq; CREATE TABLE table1 ( col_a SMALLINT NOT NULL DEFAULT NEXTVAL('table1_seq'), col_b INTEGER NOT NULL, CHECK (col_b>=0) ); ALTER SEQUENCE table1_seq OWNED BY table1.col_a; |
如果要测试MySQL的不同之处,请在MySQL数据库上运行以下内容:
1 2 3 4 5 6 7 8 | CREATE TABLE table1 ( uid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, col_b INT UNSIGNED NOT NULL ); INSERT INTO table1 (col_b) VALUES(1); INSERT INTO table1 (col_b) VALUES(-1); INSERT INTO table1 (col_b) VALUES(2); |
您应该在不使用碎片的情况下获得以下信息:
1 2 3 4 5 6 7 | +-----+-------+ | uid | col_b | +-----+-------+ | 1 | 1 | | 2 | 2 | +-----+-------+ 2 ROWS IN SET (0.00 sec) |
2。手动设置串行列值可能会导致以后的查询失败。
@trev在之前的回答中指出了这一点。
要模拟此操作,请手动将uid设置为4,稍后将"冲突"。
1 | INSERT INTO table1 (uid, col_b) VALUES(5, 5); |
表数据:
1 2 3 4 5 6 | uid | col_b -----+------- 1 | 1 3 | 2 5 | 5 (3 ROWS) |
运行另一个插入:
1 | INSERT INTO table1 (col_b) VALUES(6); |
表数据:
1 2 3 4 5 6 | uid | col_b -----+------- 1 | 1 3 | 2 5 | 5 4 | 6 |
现在,如果运行另一个插入:
1 | INSERT INTO table1 (col_b) VALUES(7); |
它将失败,并显示以下错误消息:
ERROR: duplicate key value violates unique constraint"table1_pkey"
DETAIL: Key (uid)=(5) already exists.
相比之下,MySQL会处理得很好,如下所示:
1 | INSERT INTO table1 (uid, col_b) VALUES(4, 4); |
现在插入另一行而不设置uid
1 | INSERT INTO table1 (col_b) VALUES(3); |
查询没有失败,uid跳转到5:
1 2 3 4 5 6 7 8 | +-----+-------+ | uid | col_b | +-----+-------+ | 1 | 1 | | 2 | 2 | | 4 | 4 | | 5 | 3 | +-----+-------+ |
对MySQL5.6.33、Linux(x86 U64)和PostgreSQL 9.4.9进行了测试。
从Postgres 10开始,还支持SQL标准定义的标识列:
1 2 3 4 | CREATE TABLE foo ( id INTEGER generated always AS IDENTITY ); |
创建一个标识列,除非明确要求,否则不能重写该列。以下插入将失败,列定义为
1 2 | INSERT INTO foo (id) VALUES (1); |
但这可以被否决:
1 2 | INSERT INTO foo (id) overriding system VALUE VALUES (1); |
当使用选项
1 2 3 4 | CREATE TABLE foo ( id INTEGER generated BY DEFAULT AS IDENTITY ); |
当手动提供一个值时,底层序列也需要手动调整——与
默认情况下,标识列不是主键(就像
抱歉,要重新处理一个旧问题,但这是Google上出现的第一个堆栈溢出问题/答案。
这篇文章(首先出现在谷歌上)讨论了如何使用PostgreSQL 10的更新语法:https://blog.2ndquadrant.com/postgresql-10-identity-columns/
恰好是:
1 2 3 | CREATE TABLE test_new ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, ); |
希望有帮助:)
您必须小心不要直接插入序列或序列字段,否则当序列达到插入值时,您的写入将失败:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | -- Table:"test" -- DROP TABLE test; CREATE TABLE test ( "ID" SERIAL, "Rank" INTEGER NOT NULL, "GermanHeadword""text" [] NOT NULL, "PartOfSpeech""text" NOT NULL, "ExampleSentence""text" NOT NULL, "EnglishGloss""text"[] NOT NULL, CONSTRAINT"PKey" PRIMARY KEY ("ID","Rank") ) WITH ( OIDS=FALSE ); -- ALTER TABLE test OWNER TO postgres; INSERT INTO test("Rank","GermanHeadword","PartOfSpeech","ExampleSentence","EnglishGloss") VALUES (1, '{"der","die","das","den","dem","des"}', 'art', 'Der Mann küsst die Frau und das Kind schaut zu', '{"the","of the" }'); INSERT INTO test("ID","Rank","GermanHeadword","PartOfSpeech","ExampleSentence","EnglishGloss") VALUES (2, 1, '{"der","die","das"}', 'pron', 'Das ist mein Fahrrad', '{"that","those"}'); INSERT INTO test("Rank","GermanHeadword","PartOfSpeech","ExampleSentence","EnglishGloss") VALUES (1, '{"der","die","das"}', 'pron', 'Die Frau, die nebenen wohnt, hei?t Renate', '{"that","who"}'); SELECT * FROM test; |
在所问问题的上下文中,在@sereja1c对注释的回复中,创建EDOCX1[1]隐式地创建序列,因此对于上述示例-
1 | CREATE TABLE foo (id SERIAL,bar VARCHAR); |
这种方法肯定会奏效,我希望它有助于:
1 2 3 4 5 6 7 8 9 10 | CREATE TABLE fruits( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL ); INSERT INTO fruits(id,name) VALUES(DEFAULT,'apple'); OR INSERT INTO fruits VALUES(DEFAULT,'apple'); |
您可以在下一个链接中查看详细信息:http://www.postgresqltudio.com/postgresql-serial/
自PostgreSQL 10以来
1 2 3 4 | CREATE TABLE test_new ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, payload text ); |