我最近开始将我的应用程序从使用sqlite转移到Oracle,并开始遇到以下问题:
使用rails 3.2.13,Oracle 11.2.0.3.0和activerecord-oracle_enhanced-adapter(1.4.2),我的控制器中有以下内容:
def show
if params.has_key?('user_id')
@user = User.find(params[:user_id])
else
@user = current_user
end
@user_id = @user.id
@activity_date = Date.parse(params[:id])
#@activity_date = Activity.all.first.activity_date
@activities = Activity.where("user_id = ? AND activity_date = ?", @user.id, @activity_date)
logger.warn "----- count is #{@activities.count} ------"
return
应用程序 正好找到0条记录 (根据记录器输出以及@user和@activity_date的相应值)。
< / LI>development.log将生成的查询报告为:
SELECT COUNT(*)FROM“ACTIVITIES”WHERE(user_id = 10594 AND to_date(activity_date)= TO_DATE('2013-06-05','YYYY-MM-DD HH24:MI:SS'))
如果我从SQL * Plus运行此查询,我会得到4条记录 - ,我期待。 - 因此看起来AR返回的结果与查询AR返回的结果报告给我的日志之间存在差异。
此外,如果我捣乱并使用类似
之类的方式在where调用之前手动设置日期@activity_date = Activity.all.first.activity_date
第一个活动日期恰好是“正确的”活动日期,Rails返回所有4行,因此控制台和应用程序指向同一个数据库。
据我所知:
发生了什么事?我已经没有头发了。
编辑根据David Aldridge的建议,删除了在活动日期占位符的TO_DATE调用;仍然没有得到正确的结果集。 编辑根据大卫的建议:
@user_id=10594
@activity_date=Date.parse('2013-06-13')
####### **Returned wrong set of results**
####### Note class of @activity_date is Date
bundler-0.9.24 :083 > @activity_date.class
=> Date
bundler-0.9.24 :084 > Activity.where("user_id = ? AND activity_date = ?", @userid, @activity_date).explain
Activity Load (1.8ms) SELECT "ACTIVITIES".* FROM "ACTIVITIES" WHERE (user_id = NULL AND activity_date = TO_DATE('2013-06-13','YYYY-MM-DD HH24:MI:SS'))
EXPLAIN (7.8ms) EXPLAIN PLAN FOR SELECT "ACTIVITIES".* FROM "ACTIVITIES" WHERE (user_id = NULL AND activity_date = TO_DATE('2013-06-13','YYYY-MM-DD HH24:MI:SS'))
####### **Returned right set of results**
bundler-0.9.24 :089 > @activity_date=Activity.all.first.activity_date
Activity Load (1.5ms) SELECT "ACTIVITIES".* FROM "ACTIVITIES"
=> Wed, 05 Jun 2013 04:00:00 UTC +00:00
#### Note class of @activity_date is different from above**
bundler-0.9.24 :090 > @activity_date.class
=> ActiveSupport::TimeWithZone
bundler-0.9.24 :091 > Activity.where("user_id = ? AND activity_date = ?", @userid, @activity_date).explain
**And note generated query includes a time specification whereas previous query did not**
Activity Load (2.7ms) SELECT "ACTIVITIES".* FROM "ACTIVITIES" WHERE (user_id = NULL AND activity_date = TO_DATE('2013-06-05 04:00:00','YYYY-MM-DD HH24:MI:SS'))
解决 当我创建activity_date字段时,我使用了Date.civil。我忽略了认为Oracle称之为“Date”类型的实际上也包含Time组件。
由于Date.civil没有时区,我存储的activity_date本质上是一个DateTime,偏移本地时区(因为Date.civil不占用时区)。由于我的应用程序忽略了实际的时间,我通过使用DateTime.civil而不是Date.civil来计算activity_date来解决这个问题。感谢David Aldridge的帮助,并向我道歉,我没有足够的代表来支持他。
答案 0 :(得分:0)
activity_date列实际上是日期,还是需要转换为日期的字符串?
如果是前者那么to_date是错误放置的,并且不应该出现。
@activities = Activity.where("user_id = ? AND activity_date = ?", @user.id, @activity_date)
它可能在一个环境而不是另一个环境中工作的原因是环境对nls_date_parameter具有不同的值,无论是对于数据库还是对于会话。
这里有用的诊断可能是解释计划,如果rails使用DBMS_XPlan来获取计划,则应显示隐式数据转换。您应该能够通过控制台获取计划:
Activity.where("user_id = ? AND activity_date = ?", @user.id, @activity_date).explain
在SQL * Plus中运行查询,然后运行:
select * from table(dbms_xplan.display);
...应该为您提供SQL * Plus正在使用的计划。
如果你在问题中发帖,它可能有助于未来遇到问题。