PostgreSQL 中的从属 SERIAL 列
Posted
技术标签:
【中文标题】PostgreSQL 中的从属 SERIAL 列【英文标题】:Dependent SERIAL column in PostgreSQL 【发布时间】:2015-08-10 05:17:13 【问题描述】:我想在我的表中得到这个结果contacts
:
|contact_id | user_id | user_contact_id |
+-----------+------------------+----------------------+
| 1 | 1 | 1 |
+-----------+------------------+----------------------+
| 2 | 1 | 2 |
+-----------+------------------+----------------------+
| 3 | 1 | 3 |
+-----------+------------------+----------------------+
| 4 | 2 | 1 |
+-----------+------------------+----------------------+
| 5 | 2 | 2 |
+-----------+------------------+----------------------+
| 6 | 2 | 3 |
+-----------+------------------+----------------------+
| 7 | 3 | 1 |
+-----------+------------------+----------------------+
我将只插入user_id
。
INSERT INTO contacts (user_id) VALUES ($user_id);
contact_id
将自动递增,因为它是 serial
。我希望user_contact_id
也由数据库本身自动填充,因此它在并发写入时是 100% 稳定的。
【问题讨论】:
user_contact_id
的值是不是一直从1到3算?
跟进上一个相关问题。 ***.com/questions/30469032/…
由于并发问题,这并非微不足道。你需要非常精确。请澄清在您的问题中:您的 Postgres 版本? (user_id, user_contact_id)
必须是唯一的还是偶尔被骗的可以 - 可以通过 contact_id
来区分。 (会使它很多更简单。)如何处理由于DELETE
和/或UPDATE
而导致的user_contact_id
中的空白,或者它是仅INSERT
?序列中的间隙可以吗?您知道在并发负载下,serial
列中会出现预期的空白,对吧?这个用例是 few 还是 many 用户?
@ErwinBrandstetter : 我使用的是 Postgres 9.4.1,骗子不是借口,我需要一个严格的阵容,因为我要结合 user_id 使用contact_user_id,所以它必须始终是唯一的
我是否正确阅读了您的简短评论:您不会进一步澄清您的问题吗?
【参考方案1】:
INSERT INTO CONTACTS
(user_id, user_contact_id)
VALUES
($user_id, (SELECT COALESCE(MAX(user_contact_id), 0) + 1 FROM CONTACTS WHERE user_id = $user_id))
【讨论】:
Michael - 这很酷,但是并发性如何,我将在有很多客户将记录插入数据库的情况下使用它 如果有新用户,这也不起作用,因为 MAX 将返回 null 和 null+1 == null。 @SamiKuhmonen 这是真的,我同意,你有什么解决方法吗? @CodeRows 为此可以使用COALESCE
,使用COALESCE(MAX(user_contact_id), 0)+1
@CodeRows 您的并发问题是正确的。你不应该使用它——它很容易受到种族歧视。【参考方案2】:
正如其他用户建议的那样,只有 sequence
-s 或 serial
类型保证是并发安全的。
如果你真的需要让user_contact_id
“重启”每个user_id
,也许你可以使用以下视图:
create view contacts_v as
select
contact_id,
user_id,
rank() over (partition by user_id order by contact_id) as user_contact_id
from contacts;
【讨论】:
【参考方案3】:您应该使用序列作为user_contact_id
的默认值。这正是SERIAL
列类型正在做的事情。
http://www.postgresql.org/docs/9.1/static/datatype-numeric.html http://www.postgresql.org/docs/9.4/static/sql-createsequence.html
序列对于并发写入是安全的。
CREATE TABLE contacts (
contact_id SERIAL PRIMARY KEY,
user_id INTEGER,
user_contact_id SERIAL
);
INSERT INTO contacts (user_id) VALUES
(1), (1), (1), (2), (2), (2), (3);
结果如下:
> SELECT * FROM contacts;
contact_id | user_id | user_contact_id
------------+---------+-----------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 4
5 | 2 | 5
6 | 2 | 6
7 | 3 | 7
> \d contacts
Table "public.contacts"
Column | Type | Modifiers
-----------------+---------+--------------------------------------------------------------------
contact_id | integer | not null default nextval('contacts_contact_id_seq'::regclass)
user_id | integer |
user_contact_id | integer | not null default nextval('contacts_user_contact_id_seq'::regclass)
Indexes:
"contacts_pkey" PRIMARY KEY, btree (contact_id)
【讨论】:
我对原始问题的理解是,OP 希望user_contact_id
具有每个 user_id
独立增加的值。
哦,我没注意到,抱歉,如果是这样,我就删除这个答案以上是关于PostgreSQL 中的从属 SERIAL 列的主要内容,如果未能解决你的问题,请参考以下文章
使用 Hibernate 注释映射 PostgreSQL 串行类型
尝试 PostgreSQL 主从 WAL 复制时出现“主 PostgreSQL 标识符与从属 PostgreSQL 标识符不匹配”错误
为啥这个查询这么慢? - PostgreSQL - 从 SERIAL、TIMESTAMP 和 NUMERIC(6,2) 中选择