복붙노트

[SQL] 협회를 통해 쿼리는 가장 최근의 기록으로 제한 난간?

SQL

협회를 통해 쿼리는 가장 최근의 기록으로 제한 난간?

class User 
has_many :books

나는 반환하는 쿼리를해야합니다 :

그의 가장 최근의 책이 사용자 : 완전한 => 사실. 사용자의 가장 최근의 책이있는 경우 즉 : 전체 => 허위, 나는 내 결과에서 그들을 원하지 않는다.

내가 지금까지 가지고

User.joins(:books).merge(Book.where(:complete => true))

이는 약속 시작하지만 나에게 내가 원하는 결과를 제공하지 않습니다. 내가 .order ( "created_on 내림차순")을 추가하는 시도했습니다. 제한 (1) 나는 많은 기대하고 때 위의 쿼리의 끝 그러나 나는 단지 하나의 결과로 끝날.

감사!

해결법

  1. ==============================

    1.당신이 @의 rubyprince의 루비 솔루션으로 이동하지 않을 경우이는 하위 쿼리를 필요로하기 때문에 그것은 간단한 형태의에서 액티브 처리 할 수있는 것보다 더 복잡한 DB 쿼리는 사실이다. 여기에 내가 완전히 쿼리와 함께이 작업을 수행 할 방법은 다음과 같습니다

    당신이 @의 rubyprince의 루비 솔루션으로 이동하지 않을 경우이는 하위 쿼리를 필요로하기 때문에 그것은 간단한 형태의에서 액티브 처리 할 수있는 것보다 더 복잡한 DB 쿼리는 사실이다. 여기에 내가 완전히 쿼리와 함께이 작업을 수행 할 방법은 다음과 같습니다

    SELECT   users.*
    FROM     users
             INNER JOIN books on books.user_id = users.id
    WHERE    books.created_on = ( SELECT  MAX(books.created_on)
                                  FROM    books
                                  WHERE   books.user_id = users.id)
             AND books.complete = true
    GROUP BY users.id
    

    다음을 수행 할 액티브 나는이 점을 변환하려면 :

    class User
      scope :last_book_completed, joins(:books)
        .where('books.created_on = (SELECT MAX(books.created_on) FROM books WHERE books.user_id = users.id)')
        .where('books.complete = true')
        .group('users.id')
    end
    

    그런 다음 다음을 수행하여 마지막으로 완성 된 책이있는 모든 사용자의 목록을 얻을 수 있습니다 :

    User.last_book_completed
    
  2. ==============================

    2.이것은 약간의 오버 헤드를 추가하지만 복잡성을 저장하고 중요한 때 증가 나중에 속도.

    이것은 약간의 오버 헤드를 추가하지만 복잡성을 저장하고 중요한 때 증가 나중에 속도.

    책에 "most_recent"열을 추가합니다. 확실히 당신은 인덱스를 추가 확인하십시오.

    class AddMostRecentToBooks < ActiveRecord::Migration
    
      def self.change
        add_column :books, :most_recent, :boolean, :default => false, :null => false
      end
      add_index :books, :most_recent, where: :most_recent  # partial index
    
    end
    

    그런 다음 책을 저장, 업데이트 most_recent

    class Book < ActiveRecord::Base
    
      on_save :mark_most_recent
    
      def mark_most_recent
        user.books.order(:created_at => :desc).offset(1).update_all(:most_recent => false)
        user.books.order(:created_at => :desc).limit(1).update_all(:most_recent => true)
      end
    
    end
    

    지금, 당신의 쿼리에 대한

    class User < ActiveRecord::Base
    
      # Could also include and preload most-recent book this way for lists if you wanted
      has_one :most_recent_book, -> { where(:most_recent => true) }, :class_name => 'Book'
    
      scope :last_book_completed, -> { joins(:books).where(:books => { :most_recent => true, :complete => true })
    end
    

    이것은 당신이이처럼 쓸 수있는 결과는 다른 범위에서 사용할 수있는 관계이다.

    User.last_book_completed
    
  3. ==============================

    3.나는 최근에 비슷한 문제를 가로 질러 와서 여기서 나는 그것을 해결하는 방법입니다 :

    나는 최근에 비슷한 문제를 가로 질러 와서 여기서 나는 그것을 해결하는 방법입니다 :

    most_recent_book_ids = User.all.map {|user| user.books.last.id }
    results = User.joins(:books).where('books.id in (?) AND books.complete == ?', most_recent_book_ids, true).uniq
    

    우리는 액티브 방식 (별도의 SQL)을 사용하는 사용자를위한 책의 부분 집합 고려할 때 (등, 성, 마지막 n 책을, ...)을 다시 사용할 수 있습니다이 방법. 당신은 마지막 'UNIQ'원인은, 그렇지 않으면 각 사용자가 두 번 나타납니다 필요합니다 ..

  4. ==============================

    4.나는 하나의 쿼리에서 그것을 할 수있는 방법을 생각하지 못할하지만 당신은 할 수 있습니다 :

    나는 하나의 쿼리에서 그것을 할 수있는 방법을 생각하지 못할하지만 당신은 할 수 있습니다 :

    User.all.select { |user| user.books.order("created_at desc").limit(1).complete }
    
  5. ==============================

    5.여기에 범위를 사용해야합니다 - 그들은 당신의 인생을 훨씬 간단하게 만들 것입니다 (이것은 rails3의 예입니다)

    여기에 범위를 사용해야합니다 - 그들은 당신의 인생을 훨씬 간단하게 만들 것입니다 (이것은 rails3의 예입니다)

    당신의 book.rb 모델에서

    scope :completed, where("complete = ?", true)
    scope :recent, order("created_on ASC")
    

    그럼 당신은 당신이 원하는 것을 얻을 User.books.recent.completed를 호출 할 수 있습니다

  6. ==============================

    6.팬의 대답 끌 수 있으나 왼쪽에 기반 대신 내부 조인의 조인 없으며 그룹화 :

    팬의 대답 끌 수 있으나 왼쪽에 기반 대신 내부 조인의 조인 없으며 그룹화 :

    scope :with_last_book_complete, -> {
      subquery = Book.select(:id)
                     .where("books.user_id = users.id")
                     .order(created_at: :desc).limit(1)
    
      joins(<<-SQL).where(books: { complete: true })
        LEFT JOIN books
          ON books.user_id = users.id
          AND books.id = (#{subquery.to_sql})
      SQL
    }
    
  7. from https://stackoverflow.com/questions/5247886/rails-query-through-association-limited-to-most-recent-record by cc-by-sa and MIT license