0

I have finished my first real PL/SQL stored proc, this stored proc works as expected. I am new to PL/SQL, could you please point anything wrong or bad coding ?

This code is assuming a naming convention, for example, 't_company' table will use 'companyId' as its primary key and its type is number.

Thank you very much.

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;

It will call this function

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;
4

2 回答 2

3

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

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

所以,你的SEQUENCE罐头看起来像这样:

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

然后我建议你使用 mean 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 行,IDs1,2,3,...等也是如此,例如您将删除 15. 行,因为这ID15 行,您可以不再使用了。

更新:

@Ben讨论后更新答案和解决方案,谢谢。

于 2012-07-01T17:46:59.860 回答
3

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

Oracle 提供序列以便在多用户环境中有效地生成主键。使用序列生成密钥会更好。按照惯例,您会为每个表创建一个序列,即

CREATE SEQUENCE company_seq;

您的INSERT陈述将类似于

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

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

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

于 2012-07-01T17:34:33.980 回答