mysql - PostgreSQL SERIAL 与 MySQL AUTO INCREMENT?

标签 mysql postgresql auto-increment postgresql-9.5

我有这段 MySQL:

CREATE TABLE seq_test (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name TEXT
);

INSERT INTO seq_test(id, name) VALUES (1, 'one');
INSERT INTO seq_test(name) VALUES ('two');

当我尝试在 PostgreSQL 中编写此代码时:

CREATE TABLE seq_test (
  id SERIAL PRIMARY KEY,
  name TEXT
);

INSERT INTO seq_test(id, name) VALUES (1, 'one');
INSERT INTO seq_test(name) VALUES ('two');

我收到以下错误:

[23505] ERROR: duplicate key value violates unique constraint "seq_test_pkey"
  Detail: Key (id)=(1) already exists.

这是因为在 PostgreSQL 中,插入一个不会增加下一个插入的 id。如何创建我的表以使其符合 MySQL 行为?

这当然是一个人为的例子,但我正在将一个大型代码库从 MySQL 移植到 PostgreSQL 并且部分代码(我无法控制)使用两种样式(即有和没有 id)并且它们在MySQL 但不适用于 PostgreSQL。

一个丑陋的技巧是总是执行 SELECT setval('my_table_id_seq', (SELECT count(*) FROM my_table), TRUE) ...

最佳答案

对此没有unhacky解决方案:您要么坚持SERIAL 功能,要么自己处理。

但是你让我感兴趣了,我想出了这个(我希望少一点 hacky)解决方案:创建一个触发器来完成所有肮脏的工作。

触发函数

(添加了通知以便我们可以看到发生了什么):

CREATE OR REPLACE FUNCTION update_seq_val_seq_test()
  RETURNS TRIGGER AS $$
BEGIN
  RAISE NOTICE 'id is %', NEW.id;
  IF NEW.id > currval('seq_test_id_seq' :: REGCLASS)
  THEN
    RAISE NOTICE 'curval is %', currval('seq_test_id_seq' :: REGCLASS);
    PERFORM setval('seq_test_id_seq' :: REGCLASS, (NEW.id) :: BIGINT);
    RAISE NOTICE 'new curval is %', currval('seq_test_id_seq' :: REGCLASS); END IF;
  RETURN NULL;
END;
$$
LANGUAGE 'plpgsql' COST 1;

设置触发器

CREATE TRIGGER seq_test_update_serial
  AFTER INSERT ON seq_test
  FOR EACH ROW EXECUTE PROCEDURE update_seq_val_seq_test();

扣动扳机

Fast'n'dirty 测试

tests2=# insert into seq_test (name) values ('first');
NOTICE:  id is 30
INSERT 0 1
tests2=# select * from seq_test;
 id | name  
----+-------
 30 | first
(1 row)

tests2=# select currval('seq_test_id_seq'::regclass);
 currval 
---------
      30
(1 row)

tests2=# insert into seq_test (id, name) values (31, 'thirty one');
NOTICE:  id is 31
NOTICE:  curval is 30
NOTICE:  new curval is 31
INSERT 0 1
tests2=# select currval('seq_test_id_seq'::regclass);
 currval 
---------
      31
(1 row)

tests2=# select * from seq_test;
 id |    name    
----+------------
 30 | first
 31 | thirty one
(2 rows)

tests2=# insert into seq_test (name) values ('thirty dunno what');
NOTICE:  id is 32
INSERT 0 1
tests2=# insert into seq_test (id, name) values (21, 'back to the future');
NOTICE:  id is 21
INSERT 0 1
tests2=# select currval('seq_test_id_seq'::regclass);
 currval 
---------
      32
(1 row)

tests2=# select * from seq_test;
 id |        name        
----+--------------------
 30 | first
 31 | thirty one
 32 | thirty dunno what
 21 | back to the future
(4 rows)

tests2=# insert into seq_test (name) values ('thirty dunno what++');
NOTICE:  id is 33
INSERT 0 1
tests2=# select * from seq_test;
 id |        name         
----+---------------------
 30 | first
 31 | thirty one
 32 | thirty dunno what
 21 | back to the future
 33 | thirty dunno what++
(5 rows)

所以,现在 Postgres 更像您希望的那样处理这种情况,但是有很多事情需要您检查:它如何处理批量插入、回滚、这个触发器如何影响性能,以及更多有趣的事情.

关于mysql - PostgreSQL SERIAL 与 MySQL AUTO INCREMENT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36439241/

相关文章:

java - 使用mysql的模糊逻辑

PHP分页无序列表项

sql - 选择多个属性的 MAX

mysql - 插入表强制新主键

Mysql 组条目自动递增

php - 如何将多个复选框选择值放在SQL表的单独列中?

postgresql - 创建函数以创建表 Postgresql

node.js - Sequelize 在更新时抛出无效值 [Function]

java - 未提交的数据库事务和自增列

php - Mysql 分层查询忽略重复行(但它不应该!)