简体   繁体   English

在where子句中使用case语句的Oracle Missing关键字

[英]Oracle Missing keyword using case statement in where clause

I have below stored procedure for which i am getting an error as missing keyword. 我在下面的存储过程中遇到了缺少关键字的错误。 I am trying to run the sql statement by putting them into variable because i have use the database link dynamically in the sql query. 我试图通过将它们放入变量来运行sql语句,因为我已经在sql查询中动态使用了数据库链接。 I am getting the error while using case statement in merge query. 在合并查询中使用case statement时出现错误。 When i am using dbms output line to print the merge query then its printing the complete case statement instead of only ID. 当我使用dbms输出行打印合并查询时,它会打印完整的case语句而不是仅ID。

    PROCEDURE                    "EXT_SOAP_MONITORING"(IN_DB_LINK IN varchar2) AS

    LAST_SM_ID Number := 0;
    LAST_CAPT_DATE DATE;
    LAST_SM_ID_MB Number := 0;
    LAST_CAPT_DATE_MB DATE;
    l_sql VARCHAR2(5000);
    l_sql1 VARCHAR2(5000);
    DB_CONNECTION_NAME VARCHAR2(100);

    BEGIN

    Select DB_LINK INTO DB_CONNECTION_NAME FROM RATOR_MONITORING_CONFIGURATION.DB_CONNECTION WHERE DB_LINK = IN_DB_LINK;
    --DELETE FROM TEMP_SOAP_MONITORING table before inserting new data into this table
    EXECUTE IMMEDIATE 'TRUNCATE TABLE TEMP_SOAP_MONITORING';

    -- first retrieve the last id (of the newest record) which has been imported at last extraction
    --FONIC
    SELECT LAST_TASK_ID INTO LAST_SM_ID FROM CAPTURING where DB_TABLE='TEMP_SOAP_MONITORING' and DB ='FONIC_RETAIL';
    SELECT CAPTURING_DATE INTO LAST_CAPT_DATE from CAPTURING WHERE DB_TABLE='TEMP_SOAP_MONITORING' and DB ='FONIC_RETAIL';

    --MB
    SELECT LAST_TASK_ID INTO LAST_SM_ID_MB FROM CAPTURING where DB_TABLE='TEMP_SOAP_MONITORING' and DB ='MB_RETAIL';
    SELECT CAPTURING_DATE INTO LAST_CAPT_DATE_MB from CAPTURING WHERE DB_TABLE='TEMP_SOAP_MONITORING' and DB ='MB_RETAIL';

    l_sql:=
'merge into TEMP_SOAP_MONITORING TSM
using (
   select * from
(select ID,REQUEST_XML,RESPONSE_XML,WEB_SERVICE_NAME,WEB_METHOD_NAME,CREATE_DATE,ERROR_CODE,ERROR_MESSAGE from
SOAP_MONITORING@'||DB_CONNECTION_NAME||'  WHERE 
ID > (CASE WHEN '||IN_DB_LINK||' = ''FONIC_RETAIL'' THEN ' || LAST_SM_ID || ' ELSE ' || LAST_SM_ID_MB ||' END) AND
WEB_SERVICE_NAME =''RatorWebShopService''  and WEB_METHOD_NAME = ''placeShopOrder'') where rownum <=1000
) data
ON (TSM.ID = data.ID)
when not matched then
insert(ID,REQUEST_XML,RESPONSE_XML,WEB_SERVICE_NAME,WEB_METHOD_NAME,CREATE_DATE,ERROR_CODE,ERROR_MESSAGE,DB_LINK)
values(data.ID,data.REQUEST_XML,data.RESPONSE_XML,data.WEB_SERVICE_NAME,data.WEB_METHOD_NAME,data.CREATE_DATE,data.ERROR_CODE,data.ERROR_MESSAGE,'||DB_CONNECTION_NAME ||')';

DBMS_OUTPUT.PUT_LINE('lsql' || l_sql);

    DBMS_OUTPUT.PUT_LINE('lsql' || l_sql);

    execute immediate l_sql;

    END EXT_SOAP_MONITORING;

Below is my DBMS result: 以下是我的DBMS结果:

     merge into TEMP_SOAP_MONITORING TSM
using (
   select * from
(select ID,REQUEST_XML,RESPONSE_XML,WEB_SERVICE_NAME,WEB_METHOD_NAME,CREATE_DATE,ERROR_CODE,ERROR_MESSAGE from
SOAP_MONITORING@FONIC_RETAIL  WHERE 
ID > (CASE WHEN FONIC_RETAIL = 'FONIC_RETAIL' THEN 201601071130573261 ELSE 201601071130573261 END) AND
WEB_SERVICE_NAME ='RatorWebShopService'  and WEB_METHOD_NAME = 'placeShopOrder') where rownum <=1000
) data
ON (TSM.ID = data.ID)
when not matched then
insert(ID,REQUEST_XML,RESPONSE_XML,WEB_SERVICE_NAME,WEB_METHOD_NAME,CREATE_DATE,ERROR_CODE,ERROR_MESSAGE,DB_LINK)
values(data.ID,data.REQUEST_XML,data.RESPONSE_XML,data.WEB_SERVICE_NAME,data.WEB_METHOD_NAME,data.CREATE_DATE,data.ERROR_CODE,data.ERROR_MESSAGE,FONIC_RETAIL)

As well as the missing whitespace after the THEN that @KevinEsche pointed out, you're also missing an AND (or OR) after the case statement: 以及@KevinEsche指出的THEN之后缺少的空白,您还需要在case语句之后缺少AND(或OR):

<snip>
    || ' END)
WEB_SERVICE_NAME =''RatorWebShopService'' <snip> -- <---- missing and/or before web_service_name

So, looking at the merge statement which was output by your procedure, there are two issues that leap out, coincidentally on the same line: 因此,查看您的过程输出的merge语句,有两个问题同时出现在同一行上:

ID > (CASE WHEN DB_LINK = 'FONIC_RETAIL' THEN201601071130573261 ELSE  END) AND

You forgot to add in the space after the THEN in THEN' || LAST_SM_ID 你忘了在空间添加后THENTHEN' || LAST_SM_ID THEN' || LAST_SM_ID , plus you haven't catered for LAST_SM_ID_MB being null. THEN' || LAST_SM_ID ,此外您还没有考虑到LAST_SM_ID_MB为null。


Here's how I'd write the procedure 这是我编写程序的方式

procedure ext_soap_monitoring (in_db_link in varchar2)
as
  last_sm_id number := 0;
  last_capt_date date;
  last_sm_id_mb number := 0;
  last_capt_date_mb date;
  l_sql varchar2(5000);
  l_sql1 varchar2(5000);
  db_connection_name varchar2(100);

begin
  select db_link
  into   db_connection_name
  from   rator_monitoring_configuration.db_connection
  where  db_link = in_db_link;

  --DELETE FROM TEMP_SOAP_MONITORING table before inserting new data into this table
  execute immediate 'TRUNCATE TABLE TEMP_SOAP_MONITORING';

  -- first retrieve the last id (of the newest record) which has been imported at last extraction
  --FONIC
  select last_task_id, capturing_date
  into   last_sm_id, last_capt_date
  from   capturing
  where  db_table = 'TEMP_SOAP_MONITORING'
  and    db = 'FONIC_RETAIL';

  --MB
  select last_task_id, capturing_date
  into   last_sm_id_mb, last_capt_date_mb
  from   capturing
  where  db_table = 'TEMP_SOAP_MONITORING'
  and    db = 'MB_RETAIL';

  l_sql:=
'merge into temp_soap_monitoring tsm
using (select *
       from   (select id,
                      request_xml,
                      response_xml,
                      web_service_name,
                      web_method_name,
                      create_date,
                      error_code,
                      error_message
               from   soap_monitoring@'||db_connection_name||'
               where  id > (case when :db_connection_name = ''FONIC_RETAIL'' then ' || last_sm_id || ' else ' || last_sm_id_mb ||' end)
               and    web_service_name = ''RatorWebShopService''
               and    web_method_name = ''placeShopOrder'')
       where rownum <= 1000) data
on (tsm.id = data.id)
when not matched then
insert (id,
        request_xml,
        response_xml,
        web_service_name,
        web_method_name,
        create_date,
        error_code,
        error_message,
        db_link)
values (data.id,
        data.request_xml,
        data.response_xml,
        data.web_service_name,
        data.web_method_name,
        data.create_date,
        data.error_code,
        data.error_message,
        :db_connection_name)';

  dbms_output.put_line('lsql' || l_sql);

  execute immediate l_sql using db_connection_name, db_connection_name;

end ext_soap_monitoring;
/

Note the use of the bind variables to remove the literal placements of the variables in the sql itself. 请注意,使用绑定变量来删除变量在sql本身中的字面位置。 I know you can't avoid using dynamic sql to add in the database link name when you're selecting from the table, but you can use bind variables elsewhere, and this should make your code less prone to sql injection. 我知道当您从表中进行选择时,您无法避免使用动态sql来添加数据库链接名称,但是您可以在其他地方使用绑定变量,这将使您的代码不太容易进行sql注入。

Also, see how I've formatted the merge statement - yes, it takes up more room in the variable, but it is one heck of a lot more readable now! 另外,请看我如何格式化merge语句-是的,它在变量中占用了更多空间,但是现在可读性大大提高了!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM