|
前天开发工程师要求产生一个有规则的唯一编码,编码的格式是yyyymmddx#5,即最后五位每天都是从1开始计数,他们自己的实现方式是直接对表求max(id),如果前8位是当前日期,则编码后六位加1,否则产生编码的规则是:前8位是当前日期,后六位从1开始计数。。。
由于这种编码规则的需求比较多,如果没有一个很好的接口,那开发工程师每次都要为新的需求(新的表)进行编码,代码重用性差,所以决定写个产生编码的函数来实现这种需求,这需要在数据库中创建一个表来保存一些需要持久化的信息,比如当前的序列及日期,虽然效率没有sequence高,但由于数据量也不大,所以还是可以满足需求的。 表结构:test(code_name,curr_val,curr_date,code_comment); create or replace function get_serviceid(v_serviceid in varchar2) is v_code varchar2(32); v_curr_val sys_admin_code.curr_val%type; v_curr_date sys_admin_code.curr_date%type; begin --取编码的基本信息 select curr_val, curr_date into v_curr_val, v_curr_date from sys_admin_code where code_name = v_serviceid for update; --如果是当天,则只更新curr_val if trunc(v_curr_date,'dd') = trunc(sysdate,'dd') then --产生当前的编码 v_code := to_char(v_curr_date,'yyyymmdd') || v_serviceid || lpad(v_curr_val,5,'0'); --编码累加 update sys_admin_code set curr_val = v_curr_val + 1 where code_name = v_serviceid; elsif trunc(v_curr_date,'dd') < trunc(sysdate,'dd') then --编码置1 v_code := to_char(sysdate,'yyyymmdd') || v_serviceid || lpad(1,5,'0'); --如果是第二天,则需要更新curr_date与curr_val update sys_admin_code set curr_val = 2, curr_date = sysdate where code_name = v_serviceid; end if; --提交数据累计 commit;
return v_code; end; 在创建函数是没有问题的,但在执行函数时报错: 15:52:01 SQL> select get_serviceid('1') from dual; select get_serviceid('1') from dual * ERROR at line 1: ORA-14551: cannot perform a DML operation inside a query ORA-06512: at "TAOBAO.GET_SERVICEID", line 12 但在pl/sql developer上是可以调试该函数的,结果也正确,但用select get_serviceid('1') from dual;却报错,在函数内部改成用动态sql也不成,最后只有改成存储过程了事,如果一定要用函数,也有办法的,在函数中使用匿名事务,测试脚本如下所示: create table test(id number,cnt number); insert into test values(1,1); create or replace function uf_get_current return number as pragma autonomous_transaction;
v_cnt number; begin select max(cnt) into v_cnt from test;
update test set cnt = cnt + 1; commit;
return v_cnt; end; / Function created. 20:53:37 SQL> select uf_get_current from dual; UF_GET_CURRENT -------------- 1 20:53:44 SQL> select uf_get_current from dual; UF_GET_CURRENT -------------- 2 20:53:46 SQL> select uf_get_current from dual; UF_GET_CURRENT -------------- 3 20:53:48 SQL> create or replace function uf_get_current return number 20:54:03 2 as 20:54:03 3 --pragma autonomous_transaction; 20:54:03 4 20:54:03 5 v_cnt number; 20:54:03 6 begin 20:54:03 7 select max(cnt) into v_cnt 20:54:03 8 from test; 20:54:03 9 20:54:03 10 update test set cnt = cnt + 1; 20:54:03 11 commit; 20:54:03 12 20:54:03 13 return v_cnt; 20:54:03 14 end; 20:54:04 15 / Function created. 20:54:04 SQL> select uf_get_current from dual; select uf_get_current from dual * ERROR at line 1: ORA-14551: cannot perform a DML operation inside a query ORA-06512: at "TAOBAO.UF_GET_CURRENT", line 10
|