我已经完成了我的第一个真正的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;
答案 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 进行一些讨论后,答案和解决方案会更新,谢谢。