在Oracle中查找varchar的下一个id

时间:2013-05-29 09:30:23

标签: oracle plsql

我有一个varchar(50)行,它有一个唯一约束,我希望获得新插入的下一个唯一编号,但是带有给定的前缀。

我的行看起来像这样:

ID (varchar)
00010001
00010002
00010003
00080001

因此,如果我想从前缀“0001”获取下一个unqiue号码,那么它将是“00010004”,但如果我想要它作为前缀“0008”,那么它将是“00080002”。

此表中将有超过1百万个条目。有没有办法让Oracle 11执行相当快的这种操作?

我知道这个设置完全是疯了但这是我必须要处理的。我不能创建任何新表等。

3 个答案:

答案 0 :(得分:5)

您可以搜索指定前缀的最大值并将其递增:

SQL> WITH DATA AS (
  2     SELECT '00010001' id FROM DUAL UNION ALL
  3     SELECT '00010002' id FROM DUAL UNION ALL
  4     SELECT '00010003' id FROM DUAL UNION ALL
  5     SELECT '00080001' id FROM DUAL
  6  )
  7  SELECT :prefix || to_char(MAX(to_number(substr(id, 5)))+1, 'fm0000') nextval
  8    FROM DATA
  9   WHERE ID LIKE :prefix || '%';

NEXTVAL
---------
00010004

我确定你知道这是一种生成主键的低效方法。此外,它在多用户环境中不会很好地发挥,因此不会扩展。并发插入将等待然后失败,因为列上存在UNIQUE约束。

如果前缀总是相同的长度,您可以稍微减少工作量:您可以创建一个专门的索引,以最少的步骤找到最大值:

CREATE INDEX ix_fetch_max ON your_table (substr(id, 1, 4), 
                                         substr(id, 5) DESC);

然后,以下查询可以使用索引,并将在检索到的第一行停止:

SELECT id 
  FROM (SELECT substr(id, 1, 4) || substr(id, 5) id
          FROM your_table
         WHERE substr(id, 1, 4) = :prefix
         ORDER BY substr(id, 5) DESC)
 WHERE rownum = 1

如果您需要使用相同的前缀同时插入,我建议您使用DBMS_LOCK请求锁定指定的newID。如果由于某人已插入此值而导致调用失败,请尝试使用newID+1。虽然这涉及比传统序列更多的工作,但至少你的插入不会在彼此等待(可能导致死锁)。

答案 1 :(得分:3)

这对你来说是一个非常令人不满意的情况。正如其他海报所指出的那样 - 如果你不使用序列,那么你几乎肯定会遇到并发问题。我在评论中提到你存在巨大差距的可能性。这是最简单的解决方案,但是在9999次插入后你将用完数字。

也许另一种方法是为每个前缀创建一个单独的序列。如果前缀的数量相当低但可以完成,那么这只会非常实用。

ps - 您的要求>事实上,1000000条记录可能意味着你别无选择,只能重新设计数据库。

答案 2 :(得分:0)

SELECT to_char(to_number(max(id)) + 1, '00000000')
FROM mytable
WHERE id LIKE '0001%'

这里的SQLFiddle演示http://sqlfiddle.com/#!4/4f543/5/0