【问题标题】:Timestamp AT TIME ZONE in SQLSQL中的时区时间戳
【发布时间】:2016-01-25 16:40:24
【问题描述】:

我在尝试将 TIMESTAMP 值转换为作为参数(变量)给出的时区时遇到一个奇怪的错误。

下面的代码抛出 ORA-00907 异常:

ORA-00907: 缺少右括号

declare
  tz timestamp := current_timestamp;
  v_timezone varchar2(100) := '03:00';
  tz2 timestamp;
begin
--  select (tz at time zone '03:00') into tz2 from dual;
  select (tz at time zone v_timezone) 
    into tz2
    from dual;
  dbms_output.put_line(to_char(tz2,'hh24:mi:ss'));
--  dbms_output.put_line(to_char((tz at time zone v_timezone),'hh24:mi:ss'));
end;

同时,带有字符串文字的 SQL(第一个注释行)和带有变量的 PL/SQL(第二个注释行)都可以正常工作。

SQL 中的变量可能有什么问题?为什么ORA-00907

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    您只需将 v_timezone 变量括在大括号 () 中,代码如下所示

    declare
      tz timestamp := current_timestamp;
      v_timezone varchar2(100) := '03:00';
      tz2 timestamp;
    begin
      -- select (tz at time zone '03:00') into tz2 from dual;
      -- either use it as 
      -- select tz at time zone (v_timezone)
      -- or
      -- select (tz at time zone (v_timezone) )
      select (tz at time zone (v_timezone) )
        into tz2
        from dual;
      dbms_output.put_line(to_char(tz2,'hh24:mi:ss'));
    --  dbms_output.put_line(to_char((tz at time zone v_timezone),'hh24:mi:ss'));
    end;
    

    【讨论】:

    • 更短的tz2 := tz at time zone v_timezone;
    【解决方案2】:

    AT TIME ZONE 需要文字或表达式:

    expr AT
       { LOCAL
       | TIME ZONE { ' [ + | - ] hh:mi'
                   | DBTIMEZONE
                   | 'time_zone_name'
                   | expr
                   }
       }
    

    它不喜欢变量。似乎该变量被隐式地视为dbms_output 调用或任何PL/SQL 上下文中的表达式(正如Wernfried 所指出的,只是tz2 := tz at time zone v_timezone 也有效),这有点奇怪;但在 SQL 上下文中不会发生同样的事情。

    您可以通过将变量括在括号中来强制将变量转换为表达式,或者调用一个虚拟函数:

    declare
      tz timestamp := current_timestamp;
      v_timezone varchar2(100) := '03:00';
      tz2 timestamp;
    begin
    --  select (tz at time zone '03:00') into tz2 from dual;
      select tz at time zone (v_timezone) 
        into tz2
        from dual;
      dbms_output.put_line(to_char(tz2,'hh24:mi:ss'));
    --  dbms_output.put_line(to_char((tz at time zone v_timezone),'hh24:mi:ss'));
    end;
    
    PL/SQL procedure successfully completed.
    
    17:45:41
    

    基本上,删除您现在拥有的多余括号,并在变量周围使用虚拟括号。您可以改用函数,例如upper(v_timezone),但这不是必需的 - 只需将括号作为表达式进行评估就足够了。奇怪但有效......它在错误 6113282 中提到,并且自 9i 以来似乎就是这样工作的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-03
      • 2021-09-01
      • 2017-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-22
      • 2012-09-10
      相关资源
      最近更新 更多