Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Oracle中从varchar查找下一个id_Oracle_Plsql - Fatal编程技术网

在Oracle中从varchar查找下一个id

在Oracle中从varchar查找下一个id,oracle,plsql,Oracle,Plsql,我有一行是varchar(50),它有一个唯一的约束,我想为一个新的插入获取下一个唯一的数字,但是有一个给定的前缀 我的行可以如下所示: ID (varchar) 00010001 00010002 00010003 00080001 因此,如果我想从前缀“0001”中获取下一个unqiue编号,它将是“00010004”,但如果我想将其作为前缀“0008”,它将是“00080002” 该表中的条目将超过100万条。Oracle11有没有一种方法可以相当快地执行这种操作 我知道这个设置是完全疯

我有一行是varchar(50),它有一个唯一的约束,我想为一个新的插入获取下一个唯一的数字,但是有一个给定的前缀

我的行可以如下所示:

ID (varchar)
00010001
00010002
00010003
00080001
因此,如果我想从前缀“0001”中获取下一个unqiue编号,它将是“00010004”,但如果我想将其作为前缀“0008”,它将是“00080002”

该表中的条目将超过100万条。Oracle11有没有一种方法可以相当快地执行这种操作

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

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

SQLFIDLE demo在此

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

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
我相信您知道,这是一种生成主键的低效方法。此外,它在多用户环境中无法很好地发挥作用,因此无法扩展。并发插入将等待,然后失败,因为列上存在唯一约束

如果前缀的长度始终相同,则可以在一定程度上减少工作量:可以创建专门的索引,以最少的步骤数找到最大值:

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

如果需要使用相同的前缀同时进行插入,我建议您使用请求对指定的
newID
进行锁定。如果调用失败是因为有人已插入此值,请尝试使用
newID+1
。虽然这比传统的顺序需要更多的工作,但至少插入不会互相等待(可能导致死锁)。

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

也许另一种选择是为每个前缀创建一个单独的序列。这只有在前缀数量相当少的情况下才真正可行,但这是可以做到的


ps-事实上,您要求可以有超过1000000条记录,这可能意味着您别无选择,只能重新设计数据库。

设置真是太疯狂了,我们有一个使用Hibernate的持久层,所以HQL和Java可以使用。真的不需要有任何差距吗?如果不是,则可以使用序列并接受下一个数字可以是
00080004
。这当然会限制你的可用数量numbers@HughJones可能存在差距,但这并不可取。因此,我的目标是尽可能少的间隔。如果在
SELECT
之后有人插入另一行,最后一个
id
大于
SELECT
返回的行,该怎么办?@yasirasanukaev-这是他的要求吗?如果这是一个问题,他显然需要以某种方式锁定记录。甚至可能是整个表。如果前缀不总是相同的长度,但递增部分总是4个字符/数字,则可以使用
substr(id,1,length(id)-4),substr(id,-4)
。当然,这使得查询更加复杂。SQL会对和进行处理。只是为了好玩。+1是一个很好的答案:我很想通过将substring()结果转换成数字来使索引更紧凑。如果虚拟列在使用的版本中可用,那么它似乎是一个很好的用途。我认为这将是我的方法。非常感谢。并发性取决于OP计划如何使用该表。如果是在批处理作业中,这可能不是问题,如果是用于生成临时报告,也可能不是问题。