我想解决一个棘手的问题。
我有一个Oracle数据库表,其中包含许多列。
其中一列是Varchar2列,其中包含5位数的计数器(12345)。
目前,有一个用户输入数据的屏幕,它依赖于使用列中的这些值检索数据。此外,它使用这些值的知识来确定下一个自由值是什么....换句话说,如果您正在编写新记录,并且已经使用了11111,那么它将需要11112,依此类推。 / p>
现在,完全有可能在列中的数字中存在间隙...因此我需要知道下一个任意数字在列中是否有一个随机起始点,并且上限被声明为最大可用价值。
仅使用Oracle数据库解决方案,解决此问题的最佳方法是什么?
我一直致力于服务器端解决方案......但是,我觉得这对数据库服务器来说真的是一个工作......更不用说,服务器端它真的很慢。我觉得它确实需要在数据库服务器上。
我会想象一个类似的解决方案,设计服务器端将用于在数据库服务器上工作;即从记录x开始,将每个记录从那里递增1,直到你a)找到NO记录(这是你想要的),或b)达到或超过上限。
我不是甲骨文家伙;我的背景是SQL Server,但我当前的任务需要使用Oracle。
我正在看游标,功能,包......但我觉得有点不知所措。我觉得使用批量数据光标是一个很好的起点,但是真的不知道从哪里开始。
我正在寻找有关实现此方案的最佳方式的任何建议。
感谢您抽出宝贵时间阅读本文。
(编辑)正如我在下面的评论中所揭示的那样,所涉及的列实际上包含两种不同类型的编号系统,基数10(12345)和基数36(1234A)。
因此,对问题的更好描述将是,
给定一个随机起点和最大上限,求解
下一个免费号码
OR
下一个差距开始前的最后一个使用条目。
我相信到目前为止我们有一个可能的答案,可以适用于任何一种情况。
再次感谢大家的时间。
答案 0 :(得分:1)
找到第一个差距的最简单方法。嗯,如果你取一个序列和一组连续数字之间的差异,那么这些值是不变的,直到有一个间隙。因此,以下将识别由间隙分隔的每个数字序列:
select cast(counter as int) - row_number() over (order by counter)
from table t
where counter >= v_counter;
第一组的第一个值等于v_counter - 1
。你想要的不仅仅是这个值。所以:
select (case when max(counter) is null then v_counter
else cast(max(counter) as int) + 1
end)
from (select counter
from (select t.*, cast(counter as int) - row_number() over (order by counter) as grp
from table t
where counter >= v_counter
) t
where grp = cast(v_counter as int) - 1
order by counter desc
) t
where rownum = 1;
我能够轻易想到的唯一复杂因素是初始值已经免费。这就是外部case
照顾的内容。
答案 1 :(得分:0)
您可以使用CTE从最大允许值生成起始位置的所有可能值的列表,然后找到实际数据中尚不存在的最小值。
坚持使用varchar2
并使用SQL * Plus绑定变量,因为我不知道你来自哪里:
var start_counter varchar2(5)
var max_counter varchar2(5)
exec :start_counter := '11111';
exec :max_counter := '99999';
with t as (
select to_char(level + to_number(:start_counter)) as counter
from dual
connect by level + to_number(:start_counter) <= to_number(:max_counter)
)
select min(counter)
from t
where not exists (select 1 from t42 where t42.counter = t.counter);
当然,数字会有点整洁。它有点假设你有一个关于该列的索引;如果确实如此,那应该会更好一点:
with t as (
select to_char(level + to_number(:start_counter)) as counter
from dual
connect by level + to_number(:start_counter) <= to_number(:max_counter)
)
select counter
from t
where not exists (select 1 from t42 where t42.counter = t.counter)
and rownum = 1;
但是如果你这样做,如果你有两个会话都在寻找下一个免费价值,你就有可能出现竞争条件。