在Oracle中添加/更新存储过程,插入空字段或空字段

时间:2012-06-03 05:30:28

标签: sql oracle

我是使用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 因为我仍然在表中看到原始记录,所以不会发生更新。

2 个答案:

答案 0 :(得分:1)

您当前的问题是,如果您在主键中包含PROD_CDPLAN_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
);