如何将 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))
我的 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))