【问题标题】:Oracle case statement with variable带变量的 Oracle 案例语句
【发布时间】:2018-04-04 15:37:09
【问题描述】:

我有一个要求,如果今天是星期一,则运行一个查询,否则运行另一个查询。为此,我编写了以下查询,但收到以下错误消息。

DECLARE
   l_today_date VARCHAR2(15) := TO_CHAR(SYSDATE, 'DAY');
 BEGIN
   CASE l_today_date
   WHEN 'MONDAY' THEN
     (SELECT st_time AS SYS_DATE,
       start_time                          AS JOB_START_TIME,
       COALESCE (end_job,'Job Is Running') AS JOB_END_TIME,
       CASE duration_job
         WHEN ' min'
         THEN 'Job is Running'
         ELSE duration_job
       END AS JOB_DURATION,
       CASE duration_job
         WHEN ' min'
         THEN 'Job is Running'
         ELSE 'Complete'
       END AS job_status
     FROM
       (SELECT name,
         st_time,
         ABS(floor(((((st_time - lag(end_time) over (order by end_time desc))*24*60*60)/3600)*3600)/60))
         || ' min' duration_job,
         TO_CHAR(st_time, 'hh24:mi:ss')      AS start_time,
         TO_CHAR(lag(end_time)over(order by end_time desc),'hh24:mi:ss') AS end_job
       FROM sc_stask
       WHERE name IN ( '111 has started' ,'111 has ended' )
       ORDER BY st_time DESC
       )
     WHERE name = '111 has started');
   ELSE
     (SELECT st_time                       AS SYS_DATE,
       start_time                          AS JOB_START_TIME,
       COALESCE (end_job,'Job Is Running') AS JOB_END_TIME,
       CASE duration_job
         WHEN ' min'
         THEN 'Job is Running'
         ELSE duration_job
       END AS JOB_DURATION,
       CASE duration_job
         WHEN ' min'
         THEN 'Job is Running'
         ELSE 'Complete'
       END AS job_status
     FROM
       (SELECT name,
         st_time,
         ABS(floor(((((st_time - lag(end_time)over(order by end_time desc) )*24*60*60)/3600)*3600)/60))
         || ' min' duration_job,
         TO_CHAR(st_time, 'hh24:mi:ss')      AS start_time,
         TO_CHAR(lag(end_time)over(order by end_time desc),'hh24:mi:ss') AS end_job
       FROM sc_stask
       WHERE name                      IN ( '111 has started' ,'111 has completed' )
       AND TO_CHAR(st_time,'DD/MM/YYYY')=TO_CHAR(SYSDATE,'DD/MM/YYYY')
       ORDER BY st_time DESC
       )
     WHERE name = '111 has started'
     );
   END CASE;
   dbms_output.Put_line(l_today_date);
END;

这是我遇到的错误消息

 Error report -
 ORA-06550: line 6, column 6:
 PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:

    ( - + case mod new not null <an identifier>
    <a double-quoted delimited-identifier> <a bind variable>
    continue avg count current exists max min prior sql stddev
    sum variance execute forall merge time timestamp interval
    date <a string literal with character set specification>
    <a number> <a single-quoted SQL string> pipe
    <an alternatively-quoted string literal with character set specification>
    <an alternat
 ORA-06550: line 22, column 47:
 PLS-00103: Encountered the symbol "OVER" when expecting one of the following:

    . ( ) , * % & = - + < / > at in is mod remainder not rem =>
    <an exponent (**)> <> or != or ~= >= <= <> and or like like2
    like4 likec as between || member submultiset
 06550. 00000 -  "line %s, column %s:\n%s"
 *Cause:    Usually a PL/SQL compilation error.

有人可以帮我解决这个问题吗?此外,在每个 case 语句中运行的查询都可以单独工作。但是当我将它们重新组合在一起时,它们不会。

【问题讨论】:

  • 该过程是否意味着返回一个引用游标?我没有看到任何 into 保存变量或 out 参数将任何内容传递回调用者。

标签: oracle case ora-06550 pls-00103


【解决方案1】:

问题是括号;你不应该在 select 语句周围有那些:

DECLARE
   l_today_date VARCHAR2(15) := TO_CHAR(SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE=ENGLISH');
 BEGIN
   CASE l_today_date
   WHEN 'MONDAY' THEN
     SELECT st_time AS SYS_DATE,
...
     WHERE name = '111 has started';
   ELSE
     SELECT st_time                       AS SYS_DATE,
...
     WHERE name = '111 has started';
   END CASE;
   dbms_output.Put_line(l_today_date);
END;
/

我还向to_char() 添加了可选的第三个参数,因此请确保日期名称是您要搜索的名称;否则,如果有人从非英语会话中运行它,它将无法正确匹配。


顺便说一句,如果您只使用一次 l_tdoay_date 值 - 并且最后没有 dbms_output 调试调用 - 您将不需要该变量;您可以在函数调用中使用case

BEGIN
   CASE TO_CHAR(SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE=ENGLISH')
   WHEN 'MONDAY' THEN
...

您可以在此处使用if 而不是case - 两者都可以,但只检查一个值,在此示例中您可能不会从使用case 获得太多收益。


您还可以使用单个查询并将 case 语句逻辑移动到其 where 子句中,例如:

   FROM sc_stask
   WHERE name IN ( '111 has started' ,'111 has ended' )
   AND (TO_CHAR(SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE=ENGLISH') = 'MONDAY'
     OR TO_CHAR(st_time,'DD/MM/YYYY')=TO_CHAR(SYSDATE,'DD/MM/YYYY')
   )

虽然我通常将最后一部分作为OR TRUNC(st_time) = TRUNC(SYSDATE) 进行,而不是将两者都转换为字符串。无论如何,使用这种方法,您可能根本不需要 PL/SQL 块;如果您确实拥有它,那么正如@Littlefoot 提到的那样,您必须选择(或者)查询 INTO 一些东西。

【讨论】:

    【解决方案2】:

    不是CASE,而是IF

    begin
      if to_char(sysdate, 'DAY') = 'MONDAY' then
         select ... query you run on monday;
      else
         select ... query you run otherwise
      end if;
    end;
    

    [编辑:为 INTO 子句添加示例]

    SQL> set serveroutput on
    SQL>
    SQL> declare
      2    l_cnt number;
      3    l_today varchar2(10) := to_char(sysdate, 'DAY');
      4  begin
      5    if l_today = 'THURSDAY' then
      6       select count(*)
      7         into l_cnt          --> this
      8         from emp
      9         where deptno = 10;
     10    else
     11       select count(*)
     12         into l_cnt
     13         from emp
     14         where deptno <> 10;
     15    end if;
     16
     17    dbms_output.put_line('Today is ' || l_today || ' and count = ' || l_cnt);
     18  end;
     19  /
    Today is THURSDAY  and count = 11
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    【讨论】:

    • 两者都可以;只检查一个值IF 似乎是更明显的选择,但CASE 并没有错。不过,您还删除了括号,这实际上是导致错误 *8-)
    • 实际上,@Alex,在这种情况下,两者都是错误 - 没有INTO(或者我没有看到它,或者还有其他我没有注意到的东西),所以无论如何他们都会失败。
    • 你能告诉我如何使用 into 命令,因为我也无权创建表或临时表。我只是有权执行查询
    • 我编辑了我的消息并包含了一个 INTO 子句的示例。请注意 - 如果您的查询返回多于一行 - 您必须以不同的方式执行 something (例如,循环并使用相同的 INTO,或返回一个 refcursor,或...)。
    • @Littlefoot,如您所见,我需要多个列,这些列已创建为变量并能够插入其中。但是当我试图检索这些变量的值时,我无法得到它。我尝试使用 dbms_output.Put_line(v_status);但这是在 scriptoutput 选项卡中打印输出,而不是查询结果选项卡。splunk 正在考虑没有输出。此外,当我在尝试运行查询的 Splunk 中运行此程序时,我收到以下错误 java.sql.SQLException: ORA-06550: line 1, column 5: PLS-00103: Encountered the symbol "end-of -file" 预期时
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多