我在以下liquibase脚本中遇到麻烦:
<sql> MERGE INTO A config USING (SELECT 100 as id, '02.01.15 12:00:00' as CHANGED, 0 as DELETED, 1 as B FROM DUAL) src ON (src.id = config.id) WHEN NOT MATCHED THEN INSERT(id,CHANGED, DELETED, B) VALUES(src.id, src.CHANGED, src.DELETED, src.B) WHEN MATCHED THEN UPDATE SET config.B = src.B; </sql>
当我在sql标记之间插入原始代码并在数据库下运行(在SQL Developer中)时,结果是:合并了1行。
当我通过liquibase运行它时,出现错误 ORA-01843:不是有效月份 。
这怎么可能?
'02.01.15 12:00:00'不是日期,而是字符串;如果您尝试将其插入DATE数据类型列,则Oracle将尝试使用以下等效项将其转换为日期:
'02.01.15 12:00:00'
DATE
SELECT TO_DATE( '02.01.15 12:00:00', ( SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT' ) ) as CHANGED FROM DUAL
因此,如果您的NLS_DATE_FORMAT会话参数与字符串的格式不匹配,'02.01.15 12:00:00'则它将引发异常- 这是自获取以来似乎正在发生的事情ORA-01843: not a valid month。
NLS_DATE_FORMAT
ORA-01843: not a valid month
最好的解决方案是修改脚本以将字符串显式转换为日期:
MERGE INTO A config USING ( SELECT 100 as id, TO_DATE( '02.01.15 12:00:00', 'DD.MM.YY HH24:MI:SS' ) as CHANGED, 0 as DELETED, 1 as B FROM DUAL ) src ON (src.id = config.id) WHEN NOT MATCHED THEN INSERT(id,CHANGED, DELETED, B) VALUES(src.id, src.CHANGED, src.DELETED, src.B) WHEN MATCHED THEN UPDATE SET config.B = src.B;
或使用时间戳文字: TIMESTAMP '2015-01-02 12:00:00'
TIMESTAMP '2015-01-02 12:00:00'
但是您也可以创建一个登录触发器来更改NLS_DATE_FORMAT会话参数。将触发器包装在以下代码周围:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD.MM.YY HH24:MI:SS';
但是,这会将所有隐式转换中使用的日期格式从字符串更改为日期(反之亦然),因此可能会中断其他也依赖于此类隐式转换的查询。此外,每个用户都可以随时更改其会话参数,因此在登录时设置此默认值取决于他们在会话期间永不更改它。
[TL; DR] 修复您的脚本,使其不使用数据类型之间的隐式转换,而不是修改用于隐式转换的格式模型。