我们开发了一种程序,该程序将提取固定资产预测的数据并创建.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);
答案 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;
该代码尚未经过测试。我写了几行作为示例,因为我认为这比解释要好。