PostgreSQL:琐碎的INSERT第一次失败,之后成功

ssc*_*ssc 3 postgresql insert

我在一个简单的数据库中遇到的奇怪的Postgres问题让我感到困惑:如果我首先插入一个标签并明确指定其ID,然后尝试插入另一个标签而不传递ID,那么第二个插入失败.如果我第三次尝试(再次没有ID),插入成功.

DROP DATABASE IF EXISTS mydb;
CREATE DATABASE mydb;

\c mydb

DROP SCHEMA public;
CREATE SCHEMA core;

CREATE TABLE core.tag
(
    id serial PRIMARY KEY,
    title text NOT NULL
);

-- this works: all columns specified explicitly
INSERT INTO core.tag(id, title) VALUES (1, 'known tag');

-- omitting the tag ID fails with
-- ERROR:  duplicate key value violates unique constraint "tag_pkey"
-- DETAIL:  Key (id)=(1) already exists.
INSERT INTO core.tag(title) VALUES ('unknown tag');

-- this works again ?!?
INSERT INTO core.tag(title) VALUES ('unknown tag');
Run Code Online (Sandbox Code Playgroud)

这个问题似乎只发生在新创建的数据库上,一旦发生,它似乎不再发生.我从来没有遇到过这样的事情 - 到目前为止,我刚刚插入了有或没有显式ID和AFAICS的数据,没有任何事情像这样失败......

有谁知道这里发生了什么?!?

环境:Mac OSX 10.7.5上的PostgreSQL 9.1.3

a_h*_*ame 7

当然这失败了.

怎么了?

创建表时,还会创建一个序列,用于生成ID列的值.序列以1开头,但仅在指定ID列的值时使用.

现在你跑步的时候

INSERT INTO core.tag(id, title) VALUES (1, 'known tag');
Run Code Online (Sandbox Code Playgroud)

你绕过Postgres自动分配ID值,序列"保持"在一个.

现在你跑步的时候

INSERT INTO core.tag(title) VALUES ('unknown tag');
Run Code Online (Sandbox Code Playgroud)

Postgres从序列中获取下一个值 - 即1.但是该等值存在,因此插入失败.从序列中获取值后,下一个值为2,因此后续插入而未指定ID值将获得2并成功.

解决方案是永远不要在插入中包含ID列.或 - 如果您这样做 - 请求序列中的ID:

INSERT INTO core.tag(id, title) VALUES (nextval('tag_id_seq'), 'known tag');
Run Code Online (Sandbox Code Playgroud)

创建串行列时,它会自动与命名的序列关联<table_name>_<column_name>_seq.这就是我在上述声明中使用的名称.

有关串行"数据类型"如何工作的更多详细信息,请参见手册:http://www.postgresql.org/docs/current/static/datatype-numeric.html#DATATYPE-SERIAL