执行包含update和insert语句的存储过程时发出问题

时间:2017-05-15 16:48:39

标签: oracle stored-procedures plsql

我是PLSQL的新手,我正在尝试执行此处显示的存储过程。

此存储过程将检查特定行,并根据计数更新表或插入。但我整体上的错误低于此。

  

31/18 PL / SQL:ORA-00928:缺少SELECT关键字
  31/1 PL / SQL:忽略SQL语句
  37/26 PL / SQL:ORA-00933:SQL命令未正确结束
  36/1 PL / SQL:忽略SQL语句

我尽力解决它们。你能帮忙解决这个问题吗?

这是我为此任务编写的程序:

CREATE OR REPLACE PROCEDURE LPR_LP_TEST.SP_PTMS_NOTES
(
p_app_lse_s     IN mjl.app_lse_s%TYPE,
p_dt_ent_s      IN mjl.dt_ent_s%TYPE,
p_note_type_s   IN mjl.note_type_s%TYPE,
p_prcs_c        IN mjl.prcs_c%TYPE,
p_prio_c        IN mjl.prio_c%TYPE,
p_note_title_s  IN mjl.note_title_s%TYPE,
p_info1_s       IN mjl.info1_s%TYPE,
p_info2_s       IN mjl.info2_s%TYPE
)
AS
v_rowcount_i     number;
v_lien_date    mjl.info1_s%TYPE;
--v_lien_date      NMAC_PTMS_NOTEBK_SG.LIEN_DT%TYPE;
v_asst_amount    mjl.info2_s%TYPE;

BEGIN
app_lse_s:=trim(app_lse_s);
dbms_output.put_line(app_lse_s);

select LIEN_DT,ASES_PRT_1_AM 
INTO v_lien_date,v_asst_amount
from NMAC_PTMS_NOTEBK_SG
where LSE_ID ='&2';

select count(*) into v_rowcount_i from MJL where trim(app_lse_s) ='&2';

if v_rowcount_i = 0 then
begin
Insert into MJL
('app_lse_s','dt_ent_s','note_type_s','prcs_c','prio_c','note_title_s','info
1_s','Info2_s') 
values ('&2','sysdate','SPPT','Y','1','Property Tax 
Assessment','v_lien_date','v_asst_amount');
end;
else
begin
update mjl
set dt_ent_s = 'sysdate' and note_type_s = 'SPPT' and prcs_c = 'Y' and 
prio_c = '1' and note_title_s = 'Property Tax Assessment' and info1_s = 
'v_lien_date' and Info2_s = 'v_asst_amount'
where trim(app_lse_s) = '&2';
end;
end if;
commit;
end;
/

1 个答案:

答案 0 :(得分:3)

我相信你的程序应该是这样的:

CREATE OR REPLACE PROCEDURE LPR_LP_TEST.SP_PTMS_NOTES
(
p_app_lse_s     IN mjl.app_lse_s%TYPE,
p_dt_ent_s      IN mjl.dt_ent_s%TYPE,
p_note_type_s   IN mjl.note_type_s%TYPE,
p_prcs_c        IN mjl.prcs_c%TYPE,
p_prio_c        IN mjl.prio_c%TYPE,
p_note_title_s  IN mjl.note_title_s%TYPE,
p_info1_s       IN mjl.info1_s%TYPE,
p_info2_s       IN mjl.info2_s%TYPE
)
AS
  v_rowcount_i   number;
  v_lien_date    mjl.info1_s%TYPE;
  --v_lien_date    NMAC_PTMS_NOTEBK_SG.LIEN_DT%TYPE;
  v_asst_amount  mjl.info2_s%TYPE;
  v_app_lse_s    mjl.app_lse_s%TYPE;
BEGIN
  v_app_lse_s := trim(p_app_lse_s);

  -- I hope this dbms_output line is for temporary debug purposes only
  -- and will be removed in the production version!
  dbms_output.put_line(app_lse_s);

  merge into mjl tgt
    using (select lse_s app_lse_s,
                  sysdate dt_ent_s,
                  'SPPT' note_type_s,
                  'Y' prcs_c,
                  '1' prio_c,
                  'Property Tax Assessment' note_title_s,
                  lien_dt info1_s,
                  ases_prt_1_am info2_s
           from   nmac_ptms_notebk_sg
           where  lse_id = v_app_lse_s) src
      on (tgt.app_lse_s = src.app_lse_s)
  when matched then
    update set tgt.dt_ent_s = src.dt_ent_s,
               tgt.note_title_s = src.note_title_s,
               tgt.info1_s = src.info1_s,
               tgt.info2_s = src.info2_s
    where tgt.dt_end_s != src.dt_ent_s
    or    tgt.note_title_s != src.note_title_s
    or    tgt.info1_s != src.info1_s
    or    tgt.info2_s != src.info2_s
  when not matched then
    insert (tgt.app_lse_s,
            tgt.dt_ent_s,
            tgt.note_type_s,
            tgt.prcs_c,
            tgt.prio_c,
            tgt.note_title_s,
            tgt.info1_s,
            tgt.info2_s)
    values (src.app_lse_s,
            src.dt_ent_s,
            src.note_type_s,
            src.prcs_c,
            src.prio_c,
            src.note_title_s,
            src.info1_s,
            src.info2_s);

  commit;
end;
/

关于您的程序和我为完成上述程序所做的工作,您需要注意的事项:

  1. 您倾向于将所有内容都用单引号括起来。单引号用于将某些内容声明为字符串,即some_variable := 'string value'。如果你在实际上是一个标识符的东西周围加上单引号,你实际上是在告诉Oracle把它当作一个字符串 - 这将导致各种错误!您应该在标识符周围使用引号的唯一时间是标识符的名称区分大小写,并且您应该使用双引号。例如。 select * from "lower_case_tablename"。 (注意我说"应该"在这里,但这是一个指南;你可以在非区分大小写的标识符名称周围使用双引号,但是如果这样做,名称应该是大写的 - 即select * from "DUAL";)。

  2. 您的更新语句语法不正确 - 单个语句中多个列的更新用逗号分隔,而不是and s。

  3. 您的插入和更新语句周围的beginends是不必要的。

  4. 如果您要使用隐式游标(即过程体中的select ... into <variable list> from ...),则需要确保处理可能抛出的NO_DATA_FOUND和TOO_MANY_ROWS异常。

  5. 我设置了一个变量来存储由参数p_app_lse_s传入的修剪值 - 我认为这是你的意思吗?我还替换了拨打&#39;&amp; 2&#39;变量。

  6. 如果你需要进行upsert(即如果行不存在则插入,否则更新),然后考虑MERGE语句。如果你绝对必须将它们分开,那么不要先检查行的存在;首先执行插入并检查DUP_VAL_ON_INDEX错误 - 然后在异常处理程序中执行更新。或者,首先执行更新并检查SQL%ROWCOUNT以查看是否修改了行,如果没有,则执行插入操作。但是,MERGE是可取的,因为这意味着某人没有机会在分秒中在不同的会话中插入行,这使得数据库在两个语句之间进行。

  7. 通过使用MERGE语句,我能够将您的所有逻辑合并到一个SQL语句中,这使您的过程更简单,更容易调试。首先,我需要在程序中使用您的程序中的其他参数。在merge语句中更新源查询以使用参数名称替换硬编码值很容易!我将此作为练习留给你做。

  8. 如果您从nmac_ptms_notebk_sg获取info1_s和info2_s值,您真的需要p_info1_s和p_info2_s参数吗?他们似乎不需要,恕我直言。

  9. 最后,此过程一次只能处理一个app_lse_s。如果您的数据库处理是OLTP,那很好。如果它正在进行批处理,您的代码看起来像下面的伪代码:

    for each row in <this cursor>
    loop
      execute the lpr_lp_test.sp_ptms_notes procedure
    end loop
    

    然后,最好将sp_ptms_notes过程合并到调用过程中,并在单个MERGE语句中完成工作。

    ETA:如果您有一个临时表(可能是外部表或全局临时表(GTT),甚至是普通堆表),其中包含您要加载到数据库中的数据,那么您的合并语句将会变得像:

      merge into mjl tgt
        using (select trim(st.app_lse_s) app_lse_s,
                      sysdate dt_ent_s,
                      'SPPT' note_type_s,
                      'Y' prcs_c,
                      '1' prio_c,
                      'Property Tax Assessment' note_title_s,
                      npns.lien_dt info1_s,
                      npns.ases_prt_1_am info2_s
               from   staging_table st
                      inner join nmac_ptms_notebk_sg npns-- maybe left outer join?
                        on trim(st.app_lse_s) = npns.lse_s) src
          on (tgt.app_lse_s = src.app_lse_s)
      when matched then
        update set tgt.dt_ent_s = src.dt_ent_s,
                   tgt.note_title_s = src.note_title_s,
                   tgt.info1_s = src.info1_s,
                   tgt.info2_s = src.info2_s
        where tgt.dt_end_s != src.dt_ent_s
        or    tgt.note_title_s != src.note_title_s
        or    tgt.info1_s != src.info1_s
        or    tgt.info2_s != src.info2_s
      when not matched then
        insert (tgt.app_lse_s,
                tgt.dt_ent_s,
                tgt.note_type_s,
                tgt.prcs_c,
                tgt.prio_c,
                tgt.note_title_s,
                tgt.info1_s,
                tgt.info2_s)
        values (src.app_lse_s,
                src.dt_ent_s,
                src.note_type_s,
                src.prcs_c,
                src.prio_c,
                src.note_title_s,
                src.info1_s,
                src.info2_s);
    

    您可以看到我已将nmac_ptms_notebk_sg表加入登台表,并使用该表生成需要合并到mjl表中的数据集。如果文件/临时表还包含其他列的信息(dt_ent_s,note_type_s等),则可以使用登台表中的列替换硬编码值。