2

我是使用 Oracle 的新手,我正在尝试为表创建一个添加/插入存储过程。我的表中的 PROD_CD 和 PLAN_CD 字段可以没有值(空或空)你能检查我的代码并让我知道我做错了什么吗?

表定义:

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

4

2 回答 2

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_PREFERENCEUPDATEUSER_PLAN_PREFERENCELST_UPDATE_TScurrentTimestamp

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

如果您的命名约定区分列名和参数名,那么当您打算使用参数或局部变量名时,无意中使用列名会困难得多。

于 2012-06-03T06:24:26.113 回答
0

问题就在这里

如果您希望 col 不接受 null 值,则将其定义为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
);
于 2012-06-03T05:36:06.183 回答