假设我有一个具有以下结构的表:
CREATE TABLE test(
id SERIAL,
type VARCHAR(10),
sub_id INTEGER,
UNIQUE (type, sub_id)
)
我希望“sub_id”列成为特定“类型”中的计数器。例如:
id | type | sub_id
---------------------
1 | 'foo' | 1
--------------------
2 | 'foo' | 2
--------------------
3 | 'foo' | 3
--------------------
4 | 'bar' | 1
--------------------
5 | 'bar' | 2
要使用以下查询插入新行:
INSERT INTO test(type,sub_id)
SELECT 'foo', MAX(sub_id)+1
FROM test
WHERE type='foo'
但后来我发现这个查询容易受到竞争条件的影响。 将子计数器保留在类型中的正确方法是什么?
答案 0 :(得分:0)
如果事先知道可能类型的数量,我建议使用专用序列:
CREATE SEQUENCE foo_sub_id;
CREATE SEQUENCE bar_sub_id;
我不确定您的实际要求,但另一种选择当然不是实际存储sub_id
,而是在需要使用它的任何地方进行计算:
SELECT id, type, row_number() OVER (PARTITION BY type ORDER BY id) sub_id
FROM test
答案 1 :(得分:0)
如果将sub_ids放在表格中并按顺序编号而没有间隙是必不可少的,那么使用序列是不会这样做的,
因为序列可能有差距。因此,您必须锁定整个表格,然后使用原始方法。
BEGIN Transaction;
LOCK TABLE test;
INSERT INTO test(type,sub_id)
SELECT 'foo', MAX(sub_id)+1
FROM test
WHERE type='foo';
COMMIT;
如果允许有差距,只需使用id
列。
如果只是为了"看起来" Lukas Eder提出的窗口查询对我来说也很好看:
SELECT id, type,
row_number() OVER (PARTITION BY type ORDER BY id) AS sub_id
FROM test