我是使用Oracle的新手,我正在尝试为表创建一个添加/插入存储过程。我表中的PROD_CD和PLAN_CD字段没有值(空或null) 你能查一下我的代码,让我知道我做错了吗?
CREATE TABLE DCWEB.USER_PLAN_PREFERENCE
(
USERID VARCHAR2(40) NOT NULL,
PROD_CD VARCHAR2(9) NULL,
PLAN_CD VARCHAR2(9) NULL,
STATE_LST VARCHAR2(2) NOT NULL,
STATE_NM VARCHAR2(40) NOT NULL,
LST_UPDATE_TS TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
);
ALTER TABLE DCWEB.USER_PLAN_PREFERENCE
ADD CONSTRAINT USER_PLAN_PREFERENCE_XPK PRIMARY KEY (USERID, PROD_CD, PLAN_CD);
-- Grant/Revoke object privileges
grant select, insert, update, delete on DCWEB.USER_PLAN_PREFERENCE to HIGGIB1;
procedure setUserPlanPref (
userid in varchar2,
prod_cd in varchar2,
plan_cd in varchar2,
state_lst in varchar2,
state_nm in varchar2
)
is
currentTimestamp timestamp := current_timestamp;
begin
insert into user_plan_preference (userid, prod_cd, plan_cd, state_lst, state_nm, lst_update_ts)
values (upper(userid), upper(prod_cd), upper(plan_cd), upper(state_lst), upper(state_nm), currentTimestamp);
commit;
exception
when dup_val_on_index then
begin
update user_plan_preference up set
up.userid = upper(userid),
up.prod_cd = upper(prod_cd),
up.plan_cd = upper(plan_cd),
up.state_lst = upper(state_lst),
up.state_nm = upper(state_nm),
up.lst_update_ts = currentTimestamp
where up.userid = upper(userid)
and up.prod_cd = upper(prod_cd)
and up.plan_cd = upper(plan_cd);
commit;
exception
when others then
rollback;
end;
when others then
rollback;
end;
end;
我无法插入一个使用值调用存储过程的记录: DCWEB4578 ,, 2P,CA,CALIFORNIA 但是当我更改为字符串“NULL”时,插入成功。 当我尝试调用存储过程来更新插入的记录时 值: DCWEB4578,“NULL”,2P,CO,COLORODO 因为我仍然在表中看到原始记录,所以不会发生更新。
答案 0 :(得分:1)
您当前的问题是,如果您在主键中包含PROD_CD
和PLAN_CD
,则主键约束将要求两列都为NOT NULL
。您可以在这些列中允许NULL
值,也可以将它们包含在主键中,但不能同时包含在这两个值中。
如果您的异常处理程序没有被写入吞下异常,那么这将更加清晰。当您编写类似这样的代码时,它几乎总是等待发生的错误
when others then
rollback;
end;
如果您要使用when others
异常处理程序,则几乎总是希望至少重新引发异常。
when others then
rollback;
raise;
end;
否则,调用者不知道发生了错误,也不知道错误是什么。如果你重新提出异常,你会看到像
这样的东西ORA-01400: cannot insert NULL into ("DCWEB"."USER_PLAN_PREFERENCE"."PROD_CD")
这至少会指出你正确的方向,并会给你一些东西在这里发布。
此外,声明与表中的列具有相同名称的参数是另一个等待发生的错误。您确实希望采用某种约定来区分参数名称和列名称。就个人而言,我将参数名称加上p_
前缀,即p_userid in varchar2,
。否则,您的代码几乎肯定不会达到您的预期。
由于列名在执行SQL语句时优先于局部变量,因此UPDATE
语句会将upper(userid)
,upper(prod_cd)
等解析为USER_PLAN_PREFERENCE
中的列表格不是传入的参数。假设您的数据始终为大写,则UPDATE
语句将更新USER_PLAN_PREFERENCE
的每一行,而不仅仅是您希望更新的一行,并且将每行的LST_UPDATE_TS
设置为currentTimestamp
。
update user_plan_preference up
set up.userid = upper(userid),
up.prod_cd = upper(prod_cd),
up.plan_cd = upper(plan_cd),
up.state_lst = upper(state_lst),
up.state_nm = upper(state_nm),
up.lst_update_ts = currentTimestamp
where up.userid = upper(userid)
and up.prod_cd = upper(prod_cd)
and up.plan_cd = upper(plan_cd);
如果您的命名约定区分列名和参数名,那么当您打算使用参数或本地变量名时,无意中使用列名会更加困难。
答案 1 :(得分:0)
问题出在这里
如果您希望col不接受空值,则将其定义为 NOT NULL 和反之亦然
CREATE TABLE DCWEB.USER_PLAN_PREFERENCE
(
USERID VARCHAR2(40) NOT NULL,
PROD_CD VARCHAR2(9) NULL,--**this should be NOT NULL**
PLAN_CD VARCHAR2(9) NULL,--**this should be NOT NULL**
STATE_LST VARCHAR2(2) NOT NULL,
STATE_NM VARCHAR2(40) NOT NULL,
LST_UPDATE_TS TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
);