0

我最近开始将我的应用程序从使用 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 的帮助,并很抱歉我没有足够的代表来支持他。

4

1 回答 1

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 正在使用的计划。

如果您将它们发布在问题中,它可能会帮助未来遇到问题的人。

于 2013-06-10T17:04:33.747 回答