在PostgreSQL中實現(xiàn)自增的三種方式
摘要: 本文介紹了在 PostgreSQL 中創(chuàng)建自增列的三種方法:直接使用序列(sequence)、使用 serial 數(shù)據(jù)類型,以及使用 identity column 語法。文章通過實際示例詳細講解了每種方法的語法、行為和使用場景。
使用生成鍵(generated key)是數(shù)據(jù)庫管理員(DBA)經(jīng)常采用的做法,主要出于性能考慮。在理想情況下,我們本可以依賴表的自然主鍵就萬事大吉。然而,使用人工主鍵已被證明對性能有益。
在這篇博客中,我不會解釋什么是主鍵或什么是自然鍵/人工鍵。如果你對數(shù)據(jù)庫設(shè)計感興趣,可以找到很多優(yōu)秀的書籍。
在這篇博客中,我將介紹在 Postgres 中實現(xiàn)自增的三種方式。
序列(Sequences)
實現(xiàn)自增數(shù)字的第一個明顯方法是使用序列(sequence)。(實際上,我們稍后會看到其他方法也依賴于序列)。
以下是如何使用序列的簡單示例:
laetitia=# create table test(id integeri primary key, value text);
CREATE TABLE
laetitia=# create sequence my_seq;
CREATE SEQUENCE
laetitia=# insert into test (select nextval('my_seq'), 'blabla');
INSERT 0 1
laetitia=# select * from test;
id | value
----+--------
1 | blabla
(1 row)但我們可以做得更好。如果我們希望 id 列自動填充序列的下一個值呢?
laetitia=# create sequence my_seq;
CREATE SEQUENCE
laetitia=# create table test (id integer default nextval('my_seq') primary key, value text);
CREATE TABLE
laetitia=# insert into test(value) values ('blabla');
INSERT 0 1
laetitia=# select * from test;
id | value
----+--------
1 | blabla
(1 row)
以上就是使用 Postgres 實現(xiàn)自增 id 的第一種方法。
Serial 數(shù)據(jù)類型
自 Postgres 8.2(2006年發(fā)布)以來,Postgres 添加了 serial 數(shù)據(jù)類型。正如 Postgres 文檔所述,它會做與我們之前相同的事情,但你只需用一個詞就能完成。(參見 www.postgresql.org/docs/curren…
laetitia=# create table test (id serial primary key, value text);
CREATE TABLE
laetitia=# insert into test (value) values ('blabla');
INSERT 0 1
laetitia=# select * from test;
id | value
----+--------
1 | blabla
(1 row)
如果查看表結(jié)構(gòu),你會發(fā)現(xiàn)已經(jīng)創(chuàng)建了一個序列,并用作 id 列的默認值:
laetitia=# \d test
Table "public.test"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+----------------------------------
id | integer | | not null | nextval('test_id_seq'::regclass)
value | text | | |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
laetitia=# \ds
List of relations
Schema | Name | Type | Owner
--------+-------------+----------+----------
public | test_id_seq | sequence | laetitia
(1 row)
Identity 列
序列是符合 SQL 標準的。然而,serial 數(shù)據(jù)類型并不符合標準。但 SQL 有一種方法可以為列創(chuàng)建自增,而不需要顯式創(chuàng)建序列。這就是 generated as identity。
根據(jù)需求不同,該語法有兩種形式。
第一種用法是當(dāng)你想將序列值作為默認值,但允許手動輸入其他值時。在這種情況下,語法是 generated by default as identity。但這不會阻止某人繞過序列直接插入值:
laetitia=# create table test (id integer generated by default as identity primary key, value text);
CREATE TABLE
laetitia=# \d test
Table "public.test"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+----------------------------------
id | integer | | not null | generated by default as identity
value | text | | |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
laetitia=# insert into test (value) values ('blabla');
INSERT 0 1
laetitia=# select * from test;
id | value
----+--------
1 | blabla
(1 row)
laetitia=# insert into test (id, value) values (2,'blabla');
INSERT 0 1
laetitia=# select * from test;
id | value
----+--------
1 | blabla
2 | blabla
(2 rows)
laetitia=# insert into test (value) values ('blabla');
ERROR: duplicate key value violates unique constraint "test_pkey"
DETAIL: Key (id)=(2) already exists.
如你所見,你可以手動添加值,然后由于序列滯后于 id 列中的最后一個數(shù)字,insert 操作會因重復(fù)鍵沖突而報錯。
為了防止這種情況發(fā)生,我們可以創(chuàng)建一個約束來阻止任何人手動向該列插入數(shù)據(jù)。這就是另一種 generated as identity 語法。
laetitia=# create table test (id integer generated always as identity primary key, value text);
CREATE TABLE
laetitia=# \d test
Table "public.test"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+------------------------------
id | integer | | not null | generated always as identity
value | text | | |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
laetitia=# insert into test (value) values ('blabla');
INSERT 0 1
laetitia=# insert into test (id, value) values (2,'blabla');
ERROR: cannot insert a non-DEFAULT value into column "id"
DETAIL: Column "id" is an identity column defined as GENERATED ALWAYS.
HINT: Use OVERRIDING SYSTEM VALUE to override.
我們?nèi)匀豢梢詸z查底層是否使用了序列:
laetitia=# \ds
Did not find any relations.
laetitia=# create table test (id integer generated always as identity primary key, value text);
CREATE TABLE
laetitia=# \ds
List of relations
Schema | Name | Type | Owner
--------+-------------+----------+----------
public | test_id_seq | sequence | laetitia
(1 row)
總結(jié)一下,有幾種方法可以為列創(chuàng)建自增值。我建議幾乎在所有情況下都使用 generated always as identity,因為此語法會添加約束以防止因手動插入而導(dǎo)致的序列不同步。當(dāng)然,如果有人想要篡改 identity 列背后的序列,只要有適當(dāng)?shù)臋?quán)限,他們總能找到方法做到這一點。
| 特性 | 序列(Sequence) | Serial | Identity 列 |
|---|---|---|---|
| 自動使用 nextval 作為默認值 | 否 | 是 | 是 |
| 非空約束 | 否 | 是 | 是 |
| 阻止手動插入 | 否 | 否 | 使用 always 時支持 |
到此這篇關(guān)于在PostgreSQL中實現(xiàn)自增的三種方式的文章就介紹到這了,更多相關(guān)PostgreSQL實現(xiàn)自增內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Postgresql 跨庫同步表及postgres_fdw的用法說明
這篇文章主要介紹了Postgresql 跨庫同步表及postgres_fdw的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
PostgreSQL 行列轉(zhuǎn)換的實現(xiàn)方法
本文主要介紹了PostgreSQL 行列轉(zhuǎn)換的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-07-07
PostgreSQL如何選擇合適的數(shù)據(jù)類型
本文詳細介紹了PostgreSQL中各種數(shù)據(jù)類型的特性、適用場景、潛在陷阱及最佳實踐,涵蓋了數(shù)值、字符、時間、布爾、枚舉、網(wǎng)絡(luò)、JSON、幾何、全文搜索、范圍、自定義類型等核心類別,并通過真實案例說明了數(shù)據(jù)類型選型的邏輯,感興趣的朋友跟隨小編一起看看吧2026-01-01
PostgreSQL運維案例之遞歸查詢死循環(huán)解決方案
PostgreSQL提供的遞歸語法是很棒的,例如可用來解決樹形查詢的問題,解決Oracle用戶connect by的語法兼容性,下面這篇文章主要給大家介紹了關(guān)于PostgreSQL運維案例之遞歸查詢死循環(huán)解決方案的相關(guān)資料,需要的朋友可以參考下2024-02-02
關(guān)于PostgreSQL突然無法啟動的排查過程及解決方法
SQL數(shù)據(jù)庫服務(wù)器無法啟動的原因可能有多種,這篇文章主要介紹了關(guān)于PostgreSQL突然無法啟動的排查過程及解決方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2025-07-07
關(guān)于向PostgreSQL數(shù)據(jù)庫插入Date類型數(shù)據(jù)報錯問題解決方案
本文給大家介紹在將數(shù)據(jù)庫從Oracle改為PostgreSQL時遇到的日期類型插入錯誤,通過使用PostgreSQL的特定語法和更改動態(tài)SQL語句解決了問題,本文給大家介紹的非常詳細,需要的朋友參考下吧2024-12-12
使用postgresql 模擬批量數(shù)據(jù)插入的案例
這篇文章主要介紹了使用postgresql 模擬批量數(shù)據(jù)插入的案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01

