2013-01-11 37 views
2

我對如下所示的微不足道的數據庫中遇到的一個奇怪的Postgres問題感到困惑:如果我先插入一個標籤並明確指定它的ID,然後嘗試插入另一個標籤沒有傳遞一個ID,那麼這第二次插入失敗。如果我第三次嘗試(再次沒有ID),則插入成功。PostgreSQL:微不足道的INSERT第一次失敗,事後成功

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,沒有任何失敗像這樣...

有沒有人有一個想法這是怎麼回事?

環境:Mac OS X上的PostgreSQL 9.1.3 10.7.5

回答

6

當然這會失敗。

會發生什麼?

當您創建表格時,還會創建一個序列來生成ID列的值。序列從1開始,但僅在您使用時使用而不是指定ID列的值。

現在,當你運行

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

你繞過Postgres的ID值的自動分配新建分配FY,序列‘停留’在一個。

現在,當你運行

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

Postgres的需要從序列中的下一個值 - 這是1.但是,alreay存在這樣的插入失敗。在從序列中獲取值後,下一個值爲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

+0

非常感謝你的快速和全面的幫助! :-)我真的很想知道爲什麼我還沒有絆倒這麼多...... – ssc

+0

一個小小的修改:在我的代碼中,我需要用模式來限定序列,所以它會是例如'... VALUES(nextval('core.tag_id_seq')...' – ssc

+0

@ssc:是的,我意識到這一點,爲了清晰起見,我已經把它拋出去了,你知道PostgreSQL中的「模式搜索路徑」嗎?那樣,你就不需要用模式名稱來限定序列。 –

相關問題