oracle PL / SQL存储过程

时间:2012-07-01 16:50:22

标签: oracle plsql

我已经完成了我的第一个真正的PL / SQL存储过程,这个存储过程按预期工作。我是PL / SQL的新手,你能指出任何错误或错误的编码吗?

此代码假设一个命名约定,例如,'t_company'表将使用'companyId'作为其主键,其类型为数字。

非常感谢。

create or replace
package body test_erp AS    
    procedure init_data is        
    begin         
       logMessage('procedure init_data');
       SAVEPOINT do_insert; 
       insert into t_company(companyId, companyName) values(gen_key('t_company'), 'IBM');
       COMMIT;
    exception
       WHEN OTHERS THEN  
            rollback to do_insert;  
            logMessage('roll back , due to '|| SQLERRM);
    end init_data;        
end test_erp;

它将调用此函数

create or replace
function gen_key(tblName varchar2)
return number is
    l_key number := 1000;

    l_tmpStr varchar(2000); -- not good, how to fix it  ?
begin
    l_tmpStr := substr(tblName, 3, length(tblName));   
    EXECUTE IMMEDIATE ' SELECT CASE WHEN MAX('||l_tmpStr||'Id) IS NULL THEN 1000 ELSE MAX('||l_tmpStr||'Id)+1 END FROM '|| tblName into l_key; 

     logmessage('gen primary key '|| tblName ||' '||l_key);
    return l_key;
end;

2 个答案:

答案 0 :(得分:3)

您的key_gen程序存在问题。通过执行MAX(key)+1生成密钥很慢,并且在多用户环境中不起作用。假设您有两个用户,则两个用户相对容易看到相同的MAX(key)并尝试插入具有相同主键的行。

Oracle提供序列以便在多用户环境中高效生成主键。使用序列生成密钥会更好。通常,您将为每个表创建一个序列,即

CREATE SEQUENCE company_seq;

您的INSERT声明将类似于

insert into t_company(companyId, companyName) values(company_seq.nextval, 'IBM');

或者您可以在表格上创建一个触发器来自动填充主键。

此外,虽然可以捕获异常以便记录它们,但是您确实希望重新引发该异常,以便调用者知道INSERT失败。

答案 1 :(得分:3)

在你的情况下使用函数 gen_key 非常慢并且数据库编写不正确且效率也非常低。

所以我的建议是创建通常用于此的SEQUENCE。然后你应该创建TRIGGER为每个PK生成新的INSERT或者直接添加NEXTVAL

因此,您的SEQUENCE可能如下所示:

CREATE SEQUENCE YOUR_COMP_SEQ
  MINVALUE 1
  MAXVALUE 999999
  START WITH 1
  INCREMENT BY 1
  NOCACHE
;

然后我建议你使用意味着TRIGGER

CREATE OR REPLACE TRIGGER AUTOSET_ID_COMP
BEFORE INSERT ON t_company
FOR EACH ROW
BEGIN
   SELECT YOUR_COMP_SEQ.NEXTVAL INTO :NEW.companyId FROM DUAL;
END;

最后只需调用查询:

INSERT INTO t_company(companyName) VALUES('SomeValue');

如果您不想创建TRIGGER,那么您可以直接这样做:

INSERT INTO t_company(companyId, companyName)
VALUES(YOUR_COMP_SEQ.NEXTVAL, 'SomeValue');


注意:当然,您可以为每个TABLE创建自己的SEQUENCE,然后为每个TRIGGERS使用TABLE }。
注2:序列非常好,但是有一些问题,例如你添加到表20行,所以IDs是1,2,3,...等。例如,你将删除15.行,因为这个ID 15你不能再使用了。

<强>更新

使用 @Ben 进行一些讨论后,答案和解决方案会更新,谢谢。