ORA-01843: 无效的月份
上个文章介绍了动态LINQ库。
然后动态造了一个查询,示例如下:
//ctx是EF的DbContext,字段Value是字符串类型
await ctx.Tables.Where("As(Value,\"DateTime?\")>@0",datetime).ToListAsync();
上面的查询条件在Oracle下大概是这样:CAST("Value" AS TIMESTAMP(7))>:datetime
然后报错ORA-01843: 无效的月份,原因是Value字段的值存的是这样的格式:"yyyy-MM-dd hh:mm:ss",oracle无法识别这样格式的时间值,那么它能识别什么样的时间值呢,查下。
SELECT * FROM v$nls_parameters;
可以看到里面有很多环境参数,其中有NLS_TIMESTAMP_FORMAT和NLS_TIMESTAMP_TZ_FORMAT是我们需要注意的,它默认安装下是个很奇怪的时间格式,我们需要修改他们。
alter session set NLS_TIMESTAMP_FORMAT="YYYY-MM-DD HH24:MI:SS.FF";
alter session set NLS_TIMESTAMP_TZ_FORMAT="YYYY-MM-DD HH24:MI:SS.FF";
这样就能识别Value中的时间值了,不再报错。
不过需要注意的是这个仅仅是当前会话内有效,如果是EF中需要像下面的这样做。
await ctx.OpenConnectionAsync();
ctx.Database.ExecuteSqlRawAsync("alter session set NLS_TIMESTAMP_FORMAT=\"YYYY-MM-DD HH24:MI:SS.FF\";");
ctx.Database.ExecuteSqlRawAsync("alter session set NLS_TIMESTAMP_TZ_FORMAT=\"YYYY-MM-DD HH24:MI:SS.FF\";");
await ctx.Tables.Where("As(Value,\"DateTime?\")>@0",datetime).ToListAsync();
await ctx.CloseConnectionAsync();//注意这句需要放到finally中
你也可以修改oralce全局NLS_TIMESTAMP_FORMAT环境参数,那么代码就不需要这么改了。
如果是直接sql查询,可以修改sql语句的情况下,还可以用TO_TIMESTAMP方法使用指定的格式化字符串将Value字段转成TIMESTAMP,也能解决问题。