如何将 SQL 转换为 activerecord Rails

How to convert SQL into activerecord Rails

我的 sql 给出了我想要的结果(书中的一条记录 table)。

select * 
from books
where book_number = ? and id not in (select book_id from checkout_logs where returned_date is null) limit 1

我的最佳活跃记录尝试:

@book = Book.where(book_number: params[:book_number]).where.not(id: CheckoutLog.where(returned_date: nil)).find(1)

?是参数[:book_number]

这是我的 Rails schema.rb

ActiveRecord::Schema.define(version: 2020_12_30_171415) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "books", force: :cascade do |t|
    t.string "title"
    t.string "author"
    t.string "genre"
    t.string "subgenre"
    t.integer "pages"
    t.string "publisher"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "book_number"
  end

  create_table "checkout_logs", force: :cascade do |t|
    t.datetime "checkout_date"
    t.datetime "due_date"
    t.datetime "returned_date"
    t.bigint "user_id", null: false
    t.bigint "book_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["book_id"], name: "index_checkout_logs_on_book_id"
    t.index ["user_id"], name: "index_checkout_logs_on_user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.boolean "admin", default: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

  add_foreign_key "checkout_logs", "books"
  add_foreign_key "checkout_logs", "users"
end

我的想法是,我想从 table 中获取一本书 (id),其中给定的 book_number(想想 ISBN)在 [=35= 中没有记录] table 具有匹配的 book_id 和 returned_date 的空值。 (表示图书已签出且不可用。)

编辑: 将最后一部分从 .take 更改为 .find(1) 现在确实需要 1 条记录,问题是

.where.not(id: CheckoutLog.where(returned_date: nil)) 

部分未过滤掉有 checkout_log 记录但没有 returned_date.

的书籍

使用 includes 查询方法可能会有帮助。

Book.includes(:checkout_logs).where("books.book_number=? AND checkout_logs.returned_date IS NOT NULL", params[:book_number]).limit(1)

有关查询方法的更多信息是in the api

.where.not(id: CheckoutLog.where(returned_date: nil))

=> 我认为你过滤错误的 id,你需要按书的 id 过滤,而不是 CheckoutLog 的 id。

所以您的查询应该是:

.where.not(id: CheckoutLog.where(returned_date: nil).pluck(:book_id))