0

我想用序列号填充一列,但单个序列是不够的。如果您愿意,此列的行为会有点像“子 ID”;表中记录组的递增 id。

计划是在使用触发器插入时获取“序列中的下一个数字”,就像正常情况一样sequence可以使用正常一样。但是,不仅仅是“下一个数字”,它还需要是给定结果集中的“下一个数字”。

考虑以下示例数据,其中display_id列是我需要帮助管理的序列,它取决于记录的值group_name..的记录值

编号 | 组名 | display_id
------------------------------
  5 | 甲组 | 3
  4 | 甲组 | 2
  3 | 甲组 | 1
  2 | B组 | 2
  1 | B组 | 1

我正在考虑像这样的查询来获取“下一个数字” GroupA

select max(record_id) + 1
from my_records
where group_name = 'GroupA'

因为GroupA它返回 4,但GroupB它返回 3。

当然,我们可以使用上述查询,但会失去 a 的原子优势sequence。有什么方法可以自信地管理这样的序列吗?

我们并不担心可能会跳过数字(因为序列可能)。

编辑:
我们对由于回滚等(与序列一样)而错过一两个数字感到满意。但是,我们的要求仍然是该display_id列保持多个序列。

4

2 回答 2

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 序列。

于 2013-02-21T22:00:14.387 回答
0

在列上创建唯一的复合索引group_name + display_id

然后使用您的代码,以防引发异常 - 重新运行下一个值生成。

PS:我个人不喜欢它,但在这种情况下可能没有好的选择

于 2013-02-21T21:42:17.140 回答