【问题标题】:How to convert SQL into activerecord Rails如何将 SQL 转换为 activerecord Rails
【发布时间】:2021-01-05 00:55:37
【问题描述】:

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

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

我的想法是我想从具有给定 book_number(想想 ISBN)的 book 表中获取一本书(id),该书在 checkout_log 表中没有匹配 book_id 的记录,return_date 为 null。 (表示图书已签出且不可用。)

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

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

部分没有过滤掉有 checkout_log 记录且没有 returned_date 的书籍。

【问题讨论】:

    标签: sql ruby-on-rails database postgresql activerecord


    【解决方案1】:

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

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

    所以你的查询应该是:

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

    【讨论】:

    • 我能够使用它并在最后使用 .take 或 .first 让它工作,但是 .find(1) 和 limit(1) 都给出了(不同的)错误并且不工作这个案例。显然这是对 pluck 工作方式的限制。无论哪种方式,它现在都有效。谢谢!
    【解决方案2】:

    使用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

    【讨论】:

    • 我试过了,但没有用。因为它给了我不止一本书。我之前在使用 limit(1) 时遇到了问题,所以我将其更改为 .first 和 .take ,它们给了我一个不同的错误(从子句中丢失)。在您的链接之后,它提到 include 用于“指定要包含在结果集中的关系”。在这种情况下,我不需要结果集中的 checkout_logs。我只想要书桌上的一本书。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多