oracle - 没有序列的序列

时间:2013-02-21 20:19:12

标签: oracle sequence

我想填充一个带有序号的列,但单个序列是不够的。如果您愿意,此列的行为有点像'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列维护多个序列。

2 个答案:

答案 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:我个人不喜欢它,但在这种情况下可能没有好的选择