3

以下に示す簡単なデータベースで発生する奇妙なPostgresの問題に戸惑います。最初にタグを挿入してそのIDを明示的に指定してから、IDを渡さずに別のタグを挿入しようとすると、この2番目の挿入は失敗します。3回目(これも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');

この問題は、新しく作成されたデータベースでのみ発生するようであり、一度発生すると、再発することはないようです。私はこのようなものに出くわしたことはありません-これまでのところ、明示的なIDとAFAICSの有無にかかわらずデータを挿入しただけで、このように失敗したことはありません...

誰かがここで何が起こっているのか考えていますか?!?

環境:MacOSX10.7.5上のPostgreSQL9.1.3

4

1 に答える 1

7

もちろん、これは失敗します。

何が起こるのですか?

テーブルを作成すると、ID列の値を生成するシーケンスも作成されます。シーケンスは1から始まりますが、ID列の値を指定しない場合にのみ使用されます。

今あなたが実行すると

INSERT INTO core.tag(id, title) VALUES (1, 'known tag');

PostgresによるID値の自動割り当てをバイパスすると、シーケンスは1つに「留まり」ます。

今あなたが実行すると

INSERT INTO core.tag(title) VALUES ('unknown tag');

Postgresはシーケンスから次の値(1)を取得します。しかし、その領域が存在するため、挿入は失敗します。シーケンスから値を取得した後、次の値は2であるため、ID値を指定せずに後続の挿入で2が取得され、成功します。

解決策は、挿入物にID列を含めないことです。または、実行する場合は、シーケンスからIDを要求します。

INSERT INTO core.tag(id, title) VALUES (nextval('tag_id_seq'), 'known tag');

シリアル列が作成されると、。という名前のシーケンスに自動的に関連付けられ<table_name>_<column_name>_seqます。そして、それは私が上記のステートメントで使用した名前です。

シリアル「データ型」がどのように機能するかについての詳細は、マニュアルにあります:http ://www.postgresql.org/docs/current/static/datatype-numeric.html#DATATYPE-SERIAL

于 2013-01-11T08:52:56.087 に答える