我最近开始将我的应用程序从使用 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 的适当值)。
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 行,因此控制台和应用程序指向同一个数据库。
据我所知:
- Rails 正在生成一个有效的查询,因此进入 .where 方法的值是可以的
- 所述查询返回“正确”数量的结果,*当从 SQL*Plus 运行时*
- 控制台和应用程序指向相同的数据库
- 但 Rails 似乎“看到”了错误的结果数量。
这是怎么回事 ?我的头发快要拔出来了。
编辑根据下面大卫奥尔德里奇的建议,删除了围绕 activity_date 占位符的 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.civil 不占用时区,所以我存储的 activity_date 本质上是一个 DateTime,由本地时区偏移(因为 Date.civil 不占用时区)。由于我的应用程序忽略了实际时间,我通过使用 DateTime.civil 而不是 Date.civil 计算 activity_date 来解决这个问题。感谢 David Aldridge 的帮助,并很抱歉我没有足够的代表来支持他。