首页 > 解决方案 > 非布尔值的 Active Record:true

问题描述

我正在努力思考 ActiveRecord 查询。

我正在尝试在我的数据库中搜索 ID 为 1..100 的 GolfRetailer 对象,这些对象在他们的领域中有一些东西(不是nil:website,并且true在他们的duplicate_domain领域中没有。

这是我希望工作的查询:

GolfRetailer.where.not(website: nil, duplicate_domain: true).where(id: 1..100)

我还尝试了基本相同查询的这个变体:GolfRetailer.where.not(website: nil).where(id: 1..100, duplicate_domain: !true)

但是两者都返回一个空数组,尽管肯定有满足这些要求的记录。

当我运行时GolfRetailer.where.not(website: nil).where(id: 1..100),我得到一个数组,当我运行时,GolfRetailer.where.not(website: nil, duplicate_domain: nil).where(id: 1..100)我也得到一个数组,但所有记录都有真正的 duplicate_domain 标志,这不是我要找的。

我宁愿不搜索duplicate_domain: nil那些并不总是正确的记录(我可能还没有处理他们的域)。

为清楚起见,这里是模型的架构。

create_table "golf_retailers", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "place_id"
    t.string "website"
    t.string "formatted_address"
    t.string "google_places_name"
    t.string "email"
    t.boolean "duplicate_domain"
    t.index ["duplicate_domain"], name: "index_golf_retailers_on_duplicate_domain"
  end

为了使这个查询起作用,我缺少什么?

标签: ruby-on-railsrubyactiverecord

解决方案


发生这种情况是因为在 SQL 中执行 a 时!= TRUE,任何NULL值都不会包含在结果中。这是因为该NULL值表示未知值,因此数据库不知道如何对未知值进行任何比较操作,因此它们被排除在外。

解决此问题的一种方法是使用IS DISTINCT FROM

GolfRetailer
  .where(id: 1..100)
  .where.not(website: nil)
  .where("duplicate_domain IS DISTINCT FROM ?", true)

正如其他人所提到的,您还应该问自己,如果 aGolfRetailer具有duplicate_domain.

如果,所有GolfRetailer带有 aduplicate_domain的sNULL实际上意味着它们没有一个 ( false),那么您应该考虑NULL完全阻止该列的值。

您可以通过在具有change_column数据库迁移的列上添加 NOT NULL 约束来做到这一点。

为了添加 NOT NULL 约束,您首先需要确保列中的所有数据都具有非空值。

def change
  GolfRetailer.in_batches.update_all(duplicate_domain: false)

  change_column_null :golf_retailers, :duplicate_domain
end

如果您的应用程序处于负载状态,您还应该注意任何此类迁移可能具有的潜在性能 - 特别是如果您添加具有默认值的 NOT NULL 约束。

考虑使用Strong Migrations gem 之类的工具来帮助查找可能导致生产前停机的数据库迁移。


推荐阅读