执行存储过程“PLS-00103”时出现此错误

Posted

技术标签:

【中文标题】执行存储过程“PLS-00103”时出现此错误【英文标题】:I'm getting this error when ever I'm executing my stored procedure " PLS-00103" 【发布时间】:2015-08-17 06:47:50 【问题描述】:

我正在尝试执行存储过程,我基本上卡在 54 行“立即执行”。我正在将 SQL 语句传递到 for 循环中。请让我知道我在某处做错了吗?

CREATE OR REPLACE Procedure DE_DUP_PROC (Dy_File_Name  in USER_TABLES.table_name%type,
                                         SUPPLIER_CD   in varchar2,
                                         EXT_PHARMA_ID in varchar2,
                                         FLAG_VALUE    in varchar2,
                                         DE_REC_COUNT  out NUMBER)   --RETURN NUMBER
AS
  SEQ_NO_SHO Number(38);                          --EEEE
  WYYYYNNN VARCHAR2(250) := 'W2015021';
  YYYYNNN VARCHAR2(10);
  CUR_DATE Date;
  --De_Rec_Count Number(38) := 3456;
  DE_DUB_OUTPUT_FILE VARCHAR2(100);

  /*CURSOR De_DUB_CUR IS */
  DE_DUB_SQL_STATMNT VARCHAR2(3000) := 'SELECT S.TRANS_GUID AS OLD_TRANS_GUID,
  H.TRANS_GUID    AS NEW_TRANS_GUID,
  CASE
      WHEN H.TRANS_GUID IS NULL
      THEN 0
      ELSE 1
  END as TRN_STAT,P.INTR_PHARMACY_ID as INT_PHARMACY_ID ,S.EXTRNL_PHARMACY_ID as EXT_PHARMACY_ID ,S.PHARMACY_NM as PHARMACY_NAME ,S.PHARMACY_ADDR as PHARMACY_ADDRESS,
      S.SUPPLIERS_PSCR_DRUG_CD as SP_PSCR_DRUG_CD,  S.PSCR_DRUG_IPU_CD as PS_DRUG_IPU_CD,''IPU'' as IPU_Value,  S.PSCR_DRUG_DESC as PS_DRUG_DESC,
      S.DSPNSD_DRUG_PACK_SIZE as DS_DRUG_PACK_SIZE, S.RX_ID as R_ID,  S.RX_ITEM_SEQ as R_ITEM_SEQ,  S.RX_REPEAT_STATUS as R_REPEAT_STATUS,  S.RX_TYP as R_TYPE,
      S.EXMT_STATUS as EX_STATUS,S.PSCR_QTY as PS_QTY,  S.NRSG_HM_IND as NR_HM_IND,S.RX_DSPNSD_DT as R_DSPNSD_DT,  S.RX_DSPNSD_TM as R_DSPNSD_TM,
      S.SUPPLIERS_DSPNSD_DRUG_CD as SP_DSPNSD_DRUG_CD,  S.DSPNSD_DRUG_IPU_CD as DS_DRUG_IPU_CD, ''IPU'' as IPU_Value2,S.DSPNSD_DRUG_DESC as DS_DRUG_DESC,
      S.GENERIC_USE_MARKER as GC_USE_MARKER,  S.DSPNSD_UNIT_OF_QTY as DS_UNIT_OF_QTY,  S.DSPNSD_QTY as DS_QTY, ''EUR'' as EUR_Value1,S.COST_OF_DSPNSD_QTY as CT_OF_DSPNSD_QTY ,
      S.VERBOSE_DOSAGE as VER_DOSAGE FROM
      (SELECT stg.*,  row_number() over (partition BY key_clmns_hash ORDER BY 1) AS RN FROM '|| Dy_File_Name ||' stg ) s
      LEFT JOIN ps_pharmacy p
      ON s.extrnl_pharmacy_id = p.extrnl_pharmacy_id
      LEFT JOIN ps_rx_hist H
      ON h.key_clmns_hash        = s.key_clmnS_hash
      AND h.rx_dspnsd_dt         = s.rx_dspnsd_dt
      AND s.supplier_pharmacy_cd = h.SUPPLIER_PHARMACY_CD
      AND s.detl_clmns_hash <> h.detl_clmns_hash
      WHERE s.RN                 = 1';
BEGIN
  EXECUTE IMMEDIATE 'SELECT count(*) into DE_REC_COUNT
                       FROM  (SELECT stg.*, row_number() over ( partition BY key_clmns_hash ORDER BY 1 ) AS RN FROM '|| Dy_File_Name ||' stg ) s
                       LEFT JOIN ps_pharmacy p ON s.extrnl_pharmacy_id = p.extrnl_pharmacy_id LEFT JOIN ps_rx_hist H ON h.key_clmns_hash = s.key_clmnS_hash
                        AND h.rx_dspnsd_dt = s.rx_dspnsd_dt AND s.supplier_pharmacy_cd = h.SUPPLIER_PHARMACY_CD AND s.detl_clmns_hash <> h.detl_clmns_hash WHERE S.RN = 1';

  IF DE_REC_COUNT > 0 THEN

    --select sysdate into CUR_DATE from dual;
    --select  PROC_PD_CD into WYYYYNNN from PS_ADMIN.PS_PROC_PD where PD_STRT_DT <= CURRENT_DATE and PD_END_DT >= CURRENT_DATE;
    --select  PROC_PD_CD into WYYYYNNN from PS_ADMIN.PS_PROC_PD where PD_STRT_DT <= CURRENT_DATE and PD_END_DT >= CURRENT_DATE; -- PD_STRT_DT<='16-AUG-15' and PD_STRT_DT >= '16-AUG-15';
    select replace(WYYYYNNN,'W','') into YYYYNNN from dual;
    SELECT PS_GET_PROC_PD(SUPPLIER_CD,EXT_PHARMA_ID,YYYYNNN) into SEQ_NO_SHO FROM DUAL;
    select 'LRXIE'||FLAG_VALUE||'10_'||SUPPLIER_CD||'_'||EXT_PHARMA_ID||'_'||WYYYYNNN||'_'||SEQ_NO_SHO||'_'||DE_REC_COUNT||'.TXT' into DE_DUB_OUTPUT_FILE from dual;

    --DBMS_OUTPUT.PUT_LINE( De_Dub_Output_File );

    FOR De_Dub_rec IN  EXECUTE IMMEDIATE DE_DUB_SQL_STATMNT
    LOOP
      dbms_output.enable(100000);

      DBMS_OUTPUT.PUT_LINE ('"' || De_Dub_rec.OLD_TRANS_GUID || '"|"' || De_Dub_rec.NEW_TRANS_GUID || '"|' || De_Dub_rec.TRN_STAT || '|' ||  De_Dub_rec.INT_PHARMACY_ID || '|' || De_Dub_rec.EXT_PHARMACY_ID || '|"' ||
      De_Dub_rec.PHARMACY_NAME|| '"|"' || De_Dub_rec.PHARMACY_ADDRESS || '"|' || De_Dub_rec.SP_PSCR_DRUG_CD || '|' || De_Dub_rec.PS_DRUG_IPU_CD || '|"' || De_Dub_rec.IPU_Value || '"|"' ||
      De_Dub_rec.PS_DRUG_DESC || '"|' || De_Dub_rec.DS_DRUG_PACK_SIZE || '|"' || De_Dub_rec.R_ID || '"|' || De_Dub_rec.R_ITEM_SEQ || '|' || De_Dub_rec.R_REPEAT_STATUS || '|"' ||
      De_Dub_rec.R_TYPE || '"|"' || De_Dub_rec.EX_STATUS || '"|' || De_Dub_rec.PS_QTY || '|' || De_Dub_rec.NR_HM_IND || '|"' || De_Dub_rec.R_DSPNSD_DT || '"|' || De_Dub_rec.R_DSPNSD_TM || '|' ||
      De_Dub_rec.SP_DSPNSD_DRUG_CD || '|' || De_Dub_rec.DS_DRUG_IPU_CD|| '|"' || De_Dub_rec.IPU_Value2 || '"|"' || De_Dub_rec.DS_DRUG_DESC|| '"|' || De_Dub_rec.GC_USE_MARKER|| '|"' ||
      De_Dub_rec.DS_UNIT_OF_QTY|| '"|' || De_Dub_rec.DS_QTY|| '|"' || De_Dub_rec.EUR_Value1|| '"|' || De_Dub_rec.CT_OF_DSPNSD_QTY || '|"' || De_Dub_rec.VER_DOSAGE || '"');
    END LOOP;

    DE_REC_COUNT :=0;
  ELSE
    DE_REC_COUNT :=1;
  END IF;

END DE_DUP_PROC;
/

我收到此错误:

LINE/COL ERROR
-------- -----------------------------------------------------------------
58/44    PLS-00103: Encountered the symbol "IMMEDIATE" when expecting one
         of the following:
         . ( * @ % & - + / at loop mod remainder rem ..
         <an exponent (**)> || multiset
         The symbol ". was inserted before "IMMEDIATE" to continue.

【问题讨论】:

【参考方案1】:

您的代码中有两个错误。第一个是你得到的编译器错误。您不能在for 循环中使用execute immediate(即clearly documented in the manual)

您需要打开一个游标,然后在游标上循环。所以而不是

FOR De_Dub_rec IN  EXECUTE IMMEDIATE DE_DUB_SQL_STATMNT

你需要使用这样的东西:

OPEN De_Dub_cursor FOR DE_DUB_SQL_STATMNT;
LOOP  
  FETCH De_Dub_cursor INTO de_dub_cursor_record;
  EXIT WHEN cv%NOTFOUND;   

  ... do your stuff here

END LOOP;

当然你需要声明游标De_Dub_cursor和记录变量de_dub_cursor_record。请注意,需要使用结果返回的所有列来定义记录变量(如果我没记错的话,这基本上需要定义一个新的TYPE

在您运行代码之前,您不会显示第二个错误。对于第一个 EXECUTE IMMEDIATE,您的 SQL 字符串内部有一个 INTO variable 子句。这行不通。 into 子句不能这样使用。您需要从字符串文字中删除into DE_REC_COUNT 部分,并使用INTO 子句作为execute immediate 语句的选项。像这样的:

EXECUTE IMMEDIATE 'SELECT count(*) FROM ....'
   INTO DE_REC_COUNT;

与您的问题无关,但select ... from dual 可以替换为简单的分配。

所以不是

select replace(WYYYYNNN,'W','') into YYYYNNN from dual;

使用

YYYYNNN := replace(WYYYYNNN,'W','');

或代替:

SELECT PS_GET_PROC_PD(SUPPLIER_CD,EXT_PHARMA_ID,YYYYNNN) into SEQ_NO_SHO FROM DUAL;
select 'LRXIE'||FLAG_VALUE||'10_'||SUPPLIER_CD||'_'||EXT_PHARMA_ID||'_'||WYYYYNNN||'_'||SEQ_NO_SHO||'_'||DE_REC_COUNT||'.TXT' into DE_DUB_OUTPUT_FILE from dual;

使用

SEQ_NO_SHO := PS_GET_PROC_PD(SUPPLIER_CD,EXT_PHARMA_ID,YYYYNNN);
DE_DUB_OUTPUT_FILE := 'LRXIE'||FLAG_VALUE||'10_'||SUPPLIER_CD||'_'||EXT_PHARMA_ID||'_'||WYYYYNNN||'_'||SEQ_NO_SHO||'_'||DE_REC_COUNT||'.TXT';

【讨论】:

比我的更详细的答案和更好的光标解决方案。【参考方案2】:

首先应该是execute immediate 'select count(*) from ...' into DE_REC_COUNT;

这是我在第一次扫描时看到的,但失败是在第二次立即执行。

您应该在那里创建一个集合并立即执行查询并将批量收集到该集合中。 然后,您应该在该集合中循环并执行您所做的工作(dbms_output 的东西)。

【讨论】:

以上是关于执行存储过程“PLS-00103”时出现此错误的主要内容,如果未能解决你的问题,请参考以下文章

运行程序时出现错误 PLS-00103

ORACLE 存储过程报错 PLS-00103 求查错

在 Oracle 下创建存储过程时出错 - PLS-00103

Oracle 错误 PLS-00103

当我尝试在存储过程中声明目录时,我得到“PLS-00103:遇到符号“CREATE”...”

无法使用varchar 2-pls-00103类型创建存储过程