【问题标题】:Rails scope for null return incorrect result空的Rails范围返回不正确的结果
【发布时间】:2019-01-22 01:14:45
【问题描述】:

我想查找work_end_at IS NULL的记录。

work_end_at 的类型是datetime。 而且,我试试这个WorkingHistory.where("work_end_at IS NULL")

我得到一个空的结果。但是,id 为 532 的记录是我要查找的记录。

红宝石版本:2.1.5

rails 版本:4.0.4

rails console result

WorkingHistory.where("work_end_at IS NULL")
SELECT `working_histories`.* FROM `working_histories` WHERE (work_end_at IS NULL)
[]

编辑:

console result

# console result
WorkingHistory.where(work_end_at: [nil, ""])
SELECT `working_histories`.* FROM `working_histories` WHERE ((`working_histories`.`work_end_at` = '' OR `working_histories`.`work_end_at` IS NULL))
[]

WorkingHistory.where(work_end_at: nil)
SELECT `working_histories`.* FROM `working_histories` WHERE `working_histories`.`work_end_at` IS NULL
[]

#WorkingHistory.find(532)
SELECT `working_histories`.* FROM `working_histories` WHERE `working_histories`.`id` = 532 LIMIT 1
#<WorkingHistory:0x0055d8737a8838> {
                       :id => 532,
                  :user_id => 63,
              :contract_id => 220,
            :work_start_at => Thu, 05 Jul 2018 13:54:28 CST +08:00,
               :created_at => Thu, 05 Jul 2018 13:54:33 CST +08:00,
               :updated_at => Thu, 16 Aug 2018 11:13:21 CST +08:00,
              :work_end_at => nil,
            :work_time_sec => 3721,
    :contract_milestone_id => 822
}

# WorkingHistory model
class WorkingHistory < ActiveRecord::Base
  belongs_to :user
  belongs_to :contract
  belongs_to :contract_milestone

  has_one :memo
  has_many :snapshots
  has_many :details, class_name: 'WorkingHistoryDetail'

  scope :custom_region, -> (date) { where(work_start_at: date) }
  scope :custom_day, -> (date) { where(work_start_at: date.beginning_of_day..date.end_of_day) }
  scope :custom_week, -> (date) { where(work_start_at: date.beginning_of_week..date.end_of_week) }
  scope :custom_month, -> (date) { where(work_start_at: date.beginning_of_month..date.end_of_month) }
  scope :custom_year, -> (date) { where(work_start_at: date.beginning_of_year..date.end_of_year) }
  scope :relate, -> (datetime) { where('work_start_at < ? && work_end_at >= ?', datetime, datetime) }
  scope :current, -> { where('work_start_at < ? && work_end_at = ?', Time.zone.now, '0000-00-00 00:00:00') }
  scope :cross_cycle_working, -> { where('dayofweek(work_start_at) = ? AND dayofweek(work_end_at) = ?', 6, 1) }
  scope :not_end_or_end_at_today, -> { where('work_end_at >= ?', Time.zone.today.beginning_of_day) }
  scope :without_end_at, -> { where("work_end_at IS NULL or work_end_at = ''") }

  before_save :assign_to_contract_milestone

  def end_working?
    self.work_end_at.present?
  end

  def update_work_time_sec
    return unless self.end_working?

    limit_hours = contract.limit_hours * 3600
    total_working_time = contract_milestone.working_histories.where("working_histories.id != ?", self.id).sum(:work_time_sec)
    details_sum = self.details.summation
    if (details_sum + total_working_time) > limit_hours
      difference = (limit_hours - total_working_time) > 0 ? (limit_hours - total_working_time) : 0
      self.update!(work_time_sec: difference)
    else
      secs = details_sum > 0 ? details_sum : 0
      self.update!(work_time_sec: secs)
    end
  end

  private

  def work_end_and_yet_assign?
    work_time_sec.present? && contract_milestone_id.blank?
  end
end


# db schema

  create_table "working_histories", force: true do |t|
    t.integer  "user_id"
    t.integer  "contract_id"
    t.datetime "work_start_at"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.datetime "work_end_at"
    t.integer  "work_time_sec",         default: 0,     null: false
    t.integer  "contract_milestone_id"
    t.boolean  "finish",                default: false
  end

编辑:

#The result of querying the data directly with MySQL

mysql> SELECT * FROM working_histories where `working_histories`.`id` = 532;
+-----+---------+-------------+---------------------+---------------------+---------------------+---------------------+---------------+-----------------------+--------+
| id  | user_id | contract_id | work_start_at       | created_at          | updated_at          | work_end_at         | work_time_sec | contract_milestone_id | finish |
+-----+---------+-------------+---------------------+---------------------+---------------------+---------------------+---------------+-----------------------+--------+
| 532 |      63 |         220 | 2018-07-05 05:54:28 | 2018-07-05 05:54:33 | 2018-08-16 03:13:21 | 0000-00-00 00:00:00 |          3721 |                   822 |      1 |
+-----+---------+-------------+---------------------+---------------------+---------------------+---------------------+---------------+-----------------------+--------+
1 row in set (0.01 sec)

【问题讨论】:

  • 始终粘贴输出内容而不是图像
  • 可以添加WorkingHistory.find(532)的输出吗?
  • 你可以直接在 DB 中查询这个对象来直接查看它的值,而不需要 Rails 吗?您使用的是哪个数据库?
  • @TyroneWilson 我添加了查询的输出。
  • @mefe 我无法直接访问数据库。数据库是 AWS RDS MySQL。

标签: mysql sql ruby-on-rails scope


【解决方案1】:

升级MySQL版本后问题没有解决。

我发现MySQL schema中work_end_at的默认值是0000-00-0000:00 00:00。不同于db/schema.rb

我认为这就是我无法获得正确结果的原因。

mysql> describe working_histories;
+-----------------------+------------+------+-----+---------------------+----------------+
| Field                 | Type       | Null | Key | Default             | Extra          |
+-----------------------+------------+------+-----+---------------------+----------------+
| id                    | int(11)    | NO   | PRI | NULL                | auto_increment |
| user_id               | int(11)    | YES  | MUL | NULL                |                |
| contract_id           | int(11)    | YES  | MUL | NULL                |                |
| work_start_at         | datetime   | YES  |     | NULL                |                |
| created_at            | datetime   | YES  |     | NULL                |                |
| updated_at            | datetime   | YES  |     | NULL                |                |
| work_end_at           | datetime   | YES  |     | 0000-00-00 00:00:00 |                |
| work_time_sec         | int(11)    | NO   |     | 0                   |                |
| contract_milestone_id | int(11)    | YES  | MUL | NULL                |                |
| finish                | tinyint(1) | YES  |     | 0                   |                |
+-----------------------+------------+------+-----+---------------------+----------------+
10 rows in set (0.00 sec)

【讨论】:

    【解决方案2】:

    试试这个,

    WorkingHistory.where(work_end_at: [nil, ""])
    

    它会发现两者都有 null 或空值,如果你只想要 null 你可以删除 '' 并使用

    WorkingHistory.where(work_end_at: nil)
    

    编辑 1

    这是我尝试使用您的应用程序时的输出,对我来说很好

    【讨论】:

    • 他的两个解决方案都应该有效。查询在控制台中是什么样的?
    • 您可以在尝试上述查询时显示输出吗?
    • @Subash 我已经粘贴了上述查询的输出
    • @william 很奇怪,你能把你的工作历史模型贴出来
    • @william 看不出它不工作的任何原因?您是否可以使用您的数据库转储将您的应用程序上传到 git 存储库,以便我检查一下?
    【解决方案3】:

    基于 cmets,您对 MySQL 数据库有一点问题。在此数据库中,“空”日期时间字段的值是 0000-00-00 00:00:00,而不是 null。但是,Rails 将其显示(或“强制转换”)为 nil,因此这可能会产生误导。

    第一个解决方案是查询该值,将其视为 nil''

    第二种解决方案是更新 MySQL/Rails 版本,因为 @Subash 试图重现您的问题但无法做到,所以可能存在版本之间的一些差异。

    【讨论】:

    • 我试试这个WorkingHistory.where(work_end_at: '0000-00-00 00:00:00')。而且,我得到了正确的输出!也许版本之间存在一些差异。我会尝试升级 MySQL 版本。
    • @william 有什么更新吗?你升级 MySQL 了吗?有帮助吗?
    • 抱歉,我遇到了一些内部问题。我自己无法升级 MySQL。如果我可以升级 MySQL 版本,我会更新它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 2022-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    相关资源
    最近更新 更多