【问题标题】:oracle - sequences without a sequenceoracle - 没有序列的序列
【发布时间】:2013-02-07 07:39:32
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你最好解释一下原来的任务。您当前的解决方案尝试看起来不太好。 为什么不使用序列?
  • 如果您不关心跳过数字,是否有理由不使用单个 Oracle 序列,而只是在查询时使用分析函数,如果您想弄清楚哪个row 是第 N 行,my_other_column 值为“某个值”?
  • @zerkms 好的,我会在一秒钟内加强它
  • @JustinCave 我认为我没有很好地解释自己,让我稍微改进一下这个问题。关于查询时间函数,这里不是一个选项,因为我们希望将此值永久分配给记录。关于使用普通的Oracle序列,它会跳过太多heh,我们不介意每隔一段时间跳过一个。
  • @Sean Connolly:新问题版本仍然没有解释为什么不使用序列

标签: oracle sequence


【解决方案1】:

虽然我强烈建议不要这样做(更喜欢使用单个序列并接受会有比预期更大的间隙),但您可以构建自己的伪序列表

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

【讨论】:

  • 感谢您抽出宝贵时间回答贾斯汀。考虑到要求,这个解决方案似乎是最简单和最直接的。但是,我认为,我会遵循您的最后一点并推回要求。再次感谢!
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 2014-07-02
    • 2021-01-05
    • 2016-05-13
    • 2012-08-12
    • 1970-01-01
    • 2010-12-16
    • 2020-02-21
    • 2015-10-11
    相关资源
    最近更新 更多