2

私は 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 という値がテーブルに表示されるため、更新は行われません。

4

2 に答える 2

1

当面の問題は、主キーに and を含めるPROD_CDPLAN_CD、主キーの制約により、両方の列が であることが必要になることですNOT NULLNULLこれらの列の値を許可するか、主キーに含めることができますが、両方を含めることはできません。

これは、例外を飲み込むように例外ハンドラーが作成されていなければ、より明確でした。このようなコードを書くと、ほとんどの場合バグが発生するのを待っています

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解決されます。データが常に大文字であると仮定すると、このステートメントは次のようになります。更新する予定の 1 行だけでなく、 のすべての行を更新すると、すべての行が に設定されます。 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 に答える