我想填充一个带有序号的列,但单个序列是不够的。如果您愿意,此列的行为有点像'sub id';表中记录组的递增ID。
计划是在使用触发器插入时获取序列中的“下一个数字”,就像使用普通sequence
一样。但是,它不仅仅是“下一个数字”,而是需要成为给定结果集中的“下一个数字”。
考虑以下示例数据,其中display_id
列是我需要帮助管理的序列,它取决于group_name
的记录值..
id | group_name | display_id ------------------------------ 5 | GroupA | 3 4 | GroupA | 2 3 | GroupA | 1 2 | GroupB | 2 1 | GroupB | 1
我正在考虑像此查询这样的查询来获取GroupA
的“下一个数字”:
select max(record_id) + 1
from my_records
where group_name = 'GroupA'
对于GroupA
,它返回4,但对于GroupB
,它返回3.
当然,我们可以使用上述查询,但会失去sequence
的原子优势。有没有办法自信地管理这样的序列?
我们并不担心可能会跳过数字(如序列所示)。
修改
我们很自在地因为回滚等而错过了一两个(如序列)。但是,我们的要求仍然是display_id
列维护多个序列。
答案 0 :(得分:3)
虽然我强烈建议反对它(更喜欢使用单个序列并且只接受会有大于预期的间隙),你可以构建自己的伪序列表
CREATE TABLE my_sequences (
sequence_name VARCHAR2(30) PRIMARY KEY,
sequence_val NUMBER
);
插入几行
INSERT INTO my_sequences( sequence_name, sequence_val )
VALUES( 'GroupA', 1 );
INSERT INTO my_sequences( sequence_name, sequence_val )
VALUES( 'GroupB', 1 );
然后编写一个函数来获取下一个序列值
CREATE FUNCTION get_nextval( p_sequence_name IN VARCHAR2 )
RETURN NUMBER
IS
l_val NUMBER;
BEGIN
SELECT sequence_val
INTO l_val
FROM my_sequences
WHERE sequence_name = p_sequence_name
FOR UPDATE;
UPDATE my_sequences
SET sequence_val = sequence_val + 1
WHERE sequence_name = p_sequence_name;
RETURN l_val;
END;
这将锁定表中特定序列的行,直到检索到下一行的事务提交或回滚。与使用Oracle序列相比,这将极大地降低应用程序的可伸缩性,方法是确保一次只能为一个特定group_name
插入一个会话 - 其他会话将阻止等待序列。如果您的系统具有相对较少的并发用户数(或相对较多的group_name
值),那么您可以接受。但总的来说,这是一种糟糕的做法。根据Oracle版本的不同,您可以使用自治事务来增加并发性,但这只会给解决方案增加一点复杂性。在你真正担心可伸缩性的时候,你真的想要推翻整个设计并只使用Oracle序列。
答案 1 :(得分:0)
在group_name + display_id
列上创建唯一的综合索引。
然后使用您的代码,万一抛出异常 - 重新运行下一个值生成。
PS:我个人不喜欢它,但在这种情况下可能没有好的选择