Liquibase脚本返回ORA-01843:不是有效月份

时间:2017-12-13 10:15:44

标签: sql oracle liquibase

我在使用以下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:无效月份

怎么可能?

2 个答案:

答案 0 :(得分:1)

'02.01.15 12:00:00'不是字符串的日期;如果您尝试将其插入DATE数据类型列,那么Oracle将尝试使用以下代码将其强制转换为日期:

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后出现的情况

最佳解决方案是修改脚本以将字符串显式转换为日期:

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'

但您也可以创建一个登录触发器来更改NLS_DATE_FORMAT会话参数。围绕此代码包裹触发器:

ALTER SESSION SET NLS_DATE_FORMAT = 'DD.MM.YY HH24:MI:SS';

但是,这会将所有隐式转换中使用的日期格式从字符串更改为日期(反之亦然),因此可能会破坏其他依赖此类隐式转换的查询。此外,每个用户都可以随时更改其会话参数,因此在登录时设置此默认值依赖于他们在会话期间永远不会更改它。

[TL; DR] 修复您的脚本,不要在数据类型之间使用隐式转换,而不是修改用于隐式转换的格式模型。

答案 1 :(得分:0)

使用此脚本:

<sql>
    MERGE INTO A config
    USING (SELECT 100 as id, TO_DATE('2015/02/01 12:00:00','YYYY/MM/DD 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;
</sql>