如何?正确的sql语法,用于查找下一个可用的标识符

时间:2010-12-16 20:14:52

标签: oracle sql

我想我可以从更有经验的用户那里得到一些帮助...... 我在表格中有一个整数字段名称,我们在表格SO中将其称为SO_ID,并且根据以下规则,我需要根据以下规则计算新的SO_ID: 1)SO_ID由6个字母组成,其中前3个是区号,最后3个是该区域内的序列号。
309001个
309002个
309003个
2)所以下一个新行的SO_ID值为
309004个
3)如果有人删除SO_ID值= 309002的行,则下一个新行必须回收该值,因此下一个新行必须具有值SO_ID 309002

任何人都可以请我提供SQL函数或PL / SQL(可能是一个直接的触发器吗?)函数,它将返回我需要使用的下一个可用的SO_ID? 我估计我可以在我的sql中使用关键字rownum,但是下面的操作不能正常工作

select max(so_id),max(rownum)   from( 
select (so_id),rownum,cast(substr(cast(so_id as varchar(6)),4,3) as int) from SO 
where length(so_id)=6  
and substr(cast(so_id as varchar(6)),1,3)='309' 
and cast(substr(cast(so_id as varchar(6)),4,3) as int)=rownum 
order by so_id 
);

谢谢你的帮助!

6 个答案:

答案 0 :(得分:6)

这种逻辑充满了危险。如果两个会话计算相同的“下一个”值,或两者都尝试重用相同的“已删除”值,该怎么办?由于你的列是一个整数,你可能最好不要查询“在309001和309999之间”,但这引出了当你点击区域309中的第1000个项目时会发生什么的问题?

是否可以将SO_ID作为另一个表的外键以及唯一键?您可以使用所有有效ID预先填充父表(或使用函数根据需要生成它们),然后选择不存在子记录的最低值是一件简单的事情。

答案 1 :(得分:1)

好吧,我们提出了这个...有点工作..并发是通过唯一约束来解决的

select min(lastnumber)
from
(
select so_id,so_id-LAG(so_id, 1, so_id) OVER (ORDER BY so_id) AS diff,LAG(so_id, 1, so_id) OVER (ORDER BY so_id)as lastnumber 
from so_miso
where substr(cast(so_id as varchar(6)),1,3)='309'
and length(so_id)=6
order by so_id
)a 
where diff>1;

答案 2 :(得分:0)

你真的需要计算&在插入行时存储此值?通常最好将区域代码和日期存储在表格中并在视图中计算SO_ID,即

SELECT area_code || 
           LPAD( DENSE_RANK() OVER( PARTITION BY area_code 
                                        ORDER BY date_column ), 
                 3, 
                 '0' ) AS so_id,
       <<other columns>>
  FROM your_table

或者有一个定期运行的进程(例如每晚)使用类似的逻辑分配SO_ID。

答案 3 :(得分:0)

如果您的应用程序不是纯sql,您可以在应用程序代码中执行此操作(即:Java代码)。这会更直接。

答案 4 :(得分:0)

如果在删除行时回收数字,则在生成下一个数字时必须查阅基表。试图用数字对信息进行编码的“遗留”关系前方案,如果必须在删除后必须回收数字,那么这种方法很难实现。

如果您想避免必须扫描表以查找间隙,则删除后的例程必须将删除的编号写入“ReuseMe”列中的单独表。插入例程执行此操作:

      begins trans
         selects next-number table for update
         uses a reuseme number if available else uses the next number
         clears the reuseme number if applicable or increments the next-number in the next-number table
       commits trans

答案 5 :(得分:0)

忽略有关并发性的问题,以下内容应该给出一个不错的开始。 如果表上的“流量”足够低,请在交易期间以独占模式锁定表。

create table blah (soc_id number(6));
insert into blah select 309000 + rownum from user_tables;
delete from blah where soc_id = 309003;
commit;

create or replace function get_next (i_soc in number) return number is
  v_min number := i_soc* 1000;
  v_max number := v_min + 999;
begin
  lock table blah in exclusive mode;
  select min(rn) into v_min 
    from
    (select rownum rn from dual connect by level <= 999
    minus
    select to_number(substr(soc_id,4))
    from blah
    where soc_id between v_min and v_max);
  return v_min;
end;