如果由法国用户执行并发程序执行失败

时间:2019-04-08 00:01:33

标签: sql oracle

我们开发了一种程序,该程序将提取固定资产预测的数据并创建.csv输出。我们在Oracle应用程序中注册了并发程序。我们知道,当美国或英国的商业用户执行此程序时,它的工作正常,但是法国用户执行此程序时,它将完成并显示错误。

当我检入日志文件时,我看到创建listagg函数时程序执行失败。

 select listagg('''' || TO_CHAR(PERIOD_NAME,'MON-YY') || ''' as "' || TO_CHAR(PERIOD_NAME,'MON-YY') || '"', ',') within group (order by PERIOD_NAME)
  into   pivot_clause
  from   (select   TO_DATE(PERIOD_NAME,'MON-YYYY') PERIOD_NAME from FA_PROJ_INTERIM_RPT where request_id = p_req_id
  GROUP BY TO_DATE(PERIOD_NAME,'MON-YYYY') order by TO_DATE(PERIOD_NAME,'MON-YYYY') ASC);

2 个答案:

答案 0 :(得分:2)

首先,我同意Luc M的观点,那就是最好将数据模型更改为使用ISO 8601格式,并避免命名几个月。但我知道更改模型并非总是一种选择。

如果数据必须以英语保存,但必须通过非英语会话进行转换,则可以在TO_DATE函数中设置一个显式的NLSPARAM,以确保始终以英语进行转换。如果未设置,则NLSPARAM将使用默认会话。

例如,我相信该测试会重现您的问题:

--Returns: 2019-04-01
alter session set nls_language = 'AMERICAN';
select to_date('APR-2019', 'MON-YYYY') the_date from dual;

--Fails with: ORA-01843: ce n'est pas un mois valide
alter session set nls_language = 'CANADIAN FRENCH';
select to_date('APR-2019', 'MON-YYYY') the_date from dual;

这是修复它的代码:

--Returns: 2019-04-01
alter session set nls_language = 'AMERICAN';
select to_date('APR-2019', 'MON-YYYY', 'NLS_DATE_LANGUAGE = American') the_date from dual;

--Returns: 2019-04-01
alter session set nls_language = 'FRENCH';
select to_date('APR-2019', 'MON-YYYY', 'NLS_DATE_LANGUAGE = American') the_date from dual;

国际化很难。如果上面的代码中还有其他错误(可能是针对不同的日历),这也不会令我感到惊讶。

答案 1 :(得分:1)

问题是您尝试将日期转换为非法语日期。

要使其正常运行,您有2个选项。

从查询中删除TO_CHAR和TO_DATE。

  select listagg('''' || PERIOD_NAME || ''' as "' || PERIOD_NAME || '"', ',')   
  within group (order by PERIOD_NAME)
  into   pivot_clause
  from   (select PERIOD_NAME as PERIOD_NAME 
          from FA_PROJ_INTERIM_RPT 
          where request_id = p_req_id
          GROUP BY PERIOD_NAME
          order by PERIOD_NAME ASC
        );

将月份缩写翻译为法语(您必须对其进行编码...)

JAN --> JAN  
FEB --> FEV  
MAR --> MAR  
APR --> AVR  
MAY --> MAI  
JUN --> JUN  
JUL --> JUI  
AUG --> AOU  
SEP --> SEP  
OCT --> OCT  
NOV --> NOV  
DEC --> DEC

从一开始,PERIOD_NAME应该是2019年1月的2019-01。

排序更容易,无需翻译。

编辑

Jon Heller解释说,针对您的问题的合适解决方案是即时修改NLS_LANGUAGE值。

但是我建议您在执行查询后将其重置为原始语言,以避免其他地方出现问题

original_language := userenv( 'LANG' );

-- I suppose by French you mean French Canadian...
IF original_language = 'FRC' THEN 
   EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_LANGUAGE=AMERICAN';
END IF;

-- execute your query here

IF original_language = 'FRC' THEN 
   EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_LANGUAGE=CANADIAN FRENCH';
END IF;

该代码尚未经过测试。我写了几行作为示例,因为我认为这比解释要好。