복붙노트

[RUBY-ON-RAILS] LEFT OUTER 레일에 가입 4

RUBY-ON-RAILS

LEFT OUTER 레일에 가입 4

나는 3 개 모델을 가지고 :

class Student < ActiveRecord::Base
  has_many :student_enrollments, dependent: :destroy
  has_many :courses, through: :student_enrollments
end

class Course < ActiveRecord::Base   
    has_many :student_enrollments, dependent: :destroy
    has_many :students, through: :student_enrollments
end

class StudentEnrollment < ActiveRecord::Base
    belongs_to :student
    belongs_to :course
end

나는 특정 학생과 관련된 학생 등록 ​​계약 테이블에 존재하지 않는 과정 테이블의 코스 목록은 쿼리 바랍니다.

나는 아마도 왼쪽 가입이 갈 수있는 방법이지만, 단지 인수로 테이블을 받아 레일에 ()이 조인 보이는 것을 발견했다. 내가 원하는 일을 할 것이라고 생각한다는 SQL 쿼리는 다음과 같습니다

SELECT *
FROM Courses c LEFT JOIN StudentEnrollment se ON c.id = se.course_id
WHERE se.id IS NULL AND se.student_id = <SOME_STUDENT_ID_VALUE> and c.active = true

어떻게이 쿼리를 레일 4 방법을 실행합니까?

모든 입력이 이해된다.

해결법

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

    1.당신은 가입-SQL 너무 문자열을 전달할 수 있습니다. 예를 들어, 조인 ( "LEFT이 StudentEnrollment 자체를 가입 ON c.id = se.course_id")

    당신은 가입-SQL 너무 문자열을 전달할 수 있습니다. 예를 들어, 조인 ( "LEFT이 StudentEnrollment 자체를 가입 ON c.id = se.course_id")

    내가 사용하는 거라고하지만 레일 표준 선명도에 대한 테이블 이름 :

    joins("LEFT JOIN student_enrollments ON courses.id = student_enrollments.course_id")
    
  2. ==============================

    2.사람이 왼쪽 외부를 할 수있는 일반적인 방법을 찾고 여기 온 레일 (5)에 가입하면 #left_outer_joins 기능을 사용할 수 있습니다.

    사람이 왼쪽 외부를 할 수있는 일반적인 방법을 찾고 여기 온 레일 (5)에 가입하면 #left_outer_joins 기능을 사용할 수 있습니다.

    예를 들어 다중 조인

    루비:

    Source.
     select('sources.id', 'count(metrics.id)').
     left_outer_joins(:metrics).
     joins(:port).
     where('ports.auto_delete = ?', true).
     group('sources.id').
     having('count(metrics.id) = 0').
     all
    

    SQL :

    SELECT sources.id, count(metrics.id)
      FROM "sources"
      INNER JOIN "ports" ON "ports"."id" = "sources"."port_id"
      LEFT OUTER JOIN "metrics" ON "metrics"."source_id" = "sources"."id"
      WHERE (ports.auto_delete = 't')
      GROUP BY sources.id
      HAVING (count(metrics.id) = 0)
      ORDER BY "sources"."id" ASC
    
  3. ==============================

    3.실제로이 작업을 수행 할 수있는 "레일 웨이"가있다.

    실제로이 작업을 수행 할 수있는 "레일 웨이"가있다.

    당신은 ActiveRecrods에 대한 구조 쿼리에 사용 레일 무엇 Arel을 사용할 수 있습니다

    당신이 멋지게 그것을 전화처럼, 당신이 원하는 무엇이든 인수에 뭔가를 통과 할 수 있도록 나는 방법을 포장 것입니다 :

    class Course < ActiveRecord::Base
      ....
      def left_join_student_enrollments(some_user)
        courses = Course.arel_table
        student_entrollments = StudentEnrollment.arel_table
    
        enrollments = courses.join(student_enrollments, Arel::Nodes::OuterJoin).
                      on(courses[:id].eq(student_enrollments[:course_id])).
                      join_sources
    
        joins(enrollments).where(
          student_enrollments: {student_id: some_user.id, id: nil},
          active: true
        )
      end
      ....
    end
    

    많은 사용이 빠른 (약간 더러운) 방법도 있습니다

    Course.eager_load(:students).where(
        student_enrollments: {student_id: some_user.id, id: nil}, 
        active: true
    )
    

    eager_load가 잘 작동, 그것은 단지 당신이 (귀하의 경우처럼)가 필요하지 않을 수도 메모리에 loding 모델의 "부작용"가 레일 액티브를 참조하십시오 :: QueryMethods을 .eager_load 그것은 당신이 깔끔한 방법으로 요구하고 정확하게 수행합니다.

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

    4.결합을 포함하고 액티브가 LEFT OUTER을 수행하는 결과가 뒤에서 가입 곳 (를 빼고이 두 쿼리의 정상적인 세트를 생성 할 경우).

    결합을 포함하고 액티브가 LEFT OUTER을 수행하는 결과가 뒤에서 가입 곳 (를 빼고이 두 쿼리의 정상적인 세트를 생성 할 경우).

    당신이 뭔가를 같이 할 수 있도록 :

    Course.includes(:student_enrollments).where(student_enrollments: { course_id: nil })
    

    여기 문서 : http://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-eager-loaded-associations

  5. ==============================

    5.사용 위의 대답에 추가하면이 OUTER 어디 (ID되고 전무 등) 또는 참조하면 참조를 사용할 수있는 문자열에있는 테이블을 참조하지 않고 가입하려는 경우,이 포함되어 있습니다. 즉,이 같을 것이다 :

    사용 위의 대답에 추가하면이 OUTER 어디 (ID되고 전무 등) 또는 참조하면 참조를 사용할 수있는 문자열에있는 테이블을 참조하지 않고 가입하려는 경우,이 포함되어 있습니다. 즉,이 같을 것이다 :

    Course.includes(:student_enrollments).references(:student_enrollments)
    

    또는

    Course.includes(:student_enrollments).references(:student_enrollments).where('student_enrollments.id = ?', nil)
    

    http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-references

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

    6.당신은 쿼리로 실행할 것입니다 :

    당신은 쿼리로 실행할 것입니다 :

    Course.joins('LEFT JOIN student_enrollment on courses.id = student_enrollment.course_id')
          .where(active: true, student_enrollments: { student_id: SOME_VALUE, id: nil })
    
  7. ==============================

    7.당신은 left_joins 보석, 레일 4, 3 레일 5에서 백 포트 left_joins 방법을 사용할 수 있습니다.

    당신은 left_joins 보석, 레일 4, 3 레일 5에서 백 포트 left_joins 방법을 사용할 수 있습니다.

    Course.left_joins(:student_enrollments)
          .where('student_enrollments.id' => nil)
    
  8. ==============================

    8.나는이 오래된 질문과 오래 된 스레드가 있음을 알고 있지만 레일 5, 당신은 간단하게 할 수있는

    나는이 오래된 질문과 오래 된 스레드가 있음을 알고 있지만 레일 5, 당신은 간단하게 할 수있는

    Course.left_outer_joins(:student_enrollments)
    
  9. ==============================

    9.나는 꽤 동안 이런 종류의 문제로 어려움을 겪고, 한 번 모두를 위해 그것을 해결하기 위해 뭔가를하기로 결정했습니다. 제가 요점을 출판 주소가이 문제 : https://gist.github.com/nerde/b867cd87d580e97549f2

    나는 꽤 동안 이런 종류의 문제로 어려움을 겪고, 한 번 모두를 위해 그것을 해결하기 위해 뭔가를하기로 결정했습니다. 제가 요점을 출판 주소가이 문제 : https://gist.github.com/nerde/b867cd87d580e97549f2

    난 당신의 코드에서 원시 SQL을 작성하지 않고도 동적으로 왼쪽 당신을 위해 조인 구축 Arel 표를 사용하는 작은 AR 해킹을 만들어 :

    class ActiveRecord::Base
      # Does a left join through an association. Usage:
      #
      #     Book.left_join(:category)
      #     # SELECT "books".* FROM "books"
      #     # LEFT OUTER JOIN "categories"
      #     # ON "books"."category_id" = "categories"."id"
      #
      # It also works through association's associations, like `joins` does:
      #
      #     Book.left_join(category: :master_category)
      def self.left_join(*columns)
        _do_left_join columns.compact.flatten
      end
    
      private
    
      def self._do_left_join(column, this = self) # :nodoc:
        collection = self
        if column.is_a? Array
          column.each do |col|
            collection = collection._do_left_join(col, this)
          end
        elsif column.is_a? Hash
          column.each do |key, value|
            assoc = this.reflect_on_association(key)
            raise "#{this} has no association: #{key}." unless assoc
            collection = collection._left_join(assoc)
            collection = collection._do_left_join value, assoc.klass
          end
        else
          assoc = this.reflect_on_association(column)
          raise "#{this} has no association: #{column}." unless assoc
          collection = collection._left_join(assoc)
        end
        collection
      end
    
      def self._left_join(assoc) # :nodoc:
        source = assoc.active_record.arel_table
        pk = assoc.association_primary_key.to_sym
        joins source.join(assoc.klass.arel_table,
          Arel::Nodes::OuterJoin).on(source[assoc.foreign_key].eq(
            assoc.klass.arel_table[pk])).join_sources
      end
    end
    

    희망이 도움이.

  10. ==============================

    10.이 질문에 대한 내 원래의 게시물은 아래를 참조하십시오.

    이 질문에 대한 내 원래의 게시물은 아래를 참조하십시오.

    그 이후로, 나는 (나는 다른 버전의 포트를 할 필요 했어 미안, 내 응용 프로그램이 버전에서 동결) 액티브의 v4.0.x에 대한 내 자신의 .left_joins ()를 구현 한 :

    파일 응용 프로그램 / 모델 / 문제 / active_record_extensions.rb에 다음을 넣어 :

    module ActiveRecordBaseExtensions
        extend ActiveSupport::Concern
    
        def left_joins(*args)
            self.class.left_joins(args)
        end
    
        module ClassMethods
            def left_joins(*args)
                all.left_joins(args)
            end
        end
    end
    
    module ActiveRecordRelationExtensions
        extend ActiveSupport::Concern
    
        # a #left_joins implementation for Rails 4.0 (WARNING: this uses Rails 4.0 internals
        # and so probably only works for Rails 4.0; it'll probably need to be modified if
        # upgrading to a new Rails version, and will be obsolete in Rails 5 since it has its
        # own #left_joins implementation)
        def left_joins(*args)
            eager_load(args).construct_relation_for_association_calculations
        end
    end
    
    ActiveRecord::Base.send(:include, ActiveRecordBaseExtensions)
    ActiveRecord::Relation.send(:include, ActiveRecordRelationExtensions)
    

    나는 일반적으로 .joins을 사용하십시오 사방 지금은 () .left_joins ()을 사용할 수 있습니다.

    ----------------- 아래 ORIGINAL POST -----------------

    당신은 OUTER 여분의 열망로드 액티브 객체를 모두 사용하지 않는 결합하려는 경우, 사용 .pluck (: ID)가 외부 조인을 유지하면서 .eager_load 후 ()는 열망로드를 중단합니다. (: ID) .pluck 사용 사용시 열 이름 별명 (예 t1_r9 AS items.location가) 상기 생성 된 조회 사라 때문에 (이 독립적이라는 필드 모두 간절히로드 액티브 객체를 인스턴스화하기 위해 사용된다) 열망 로딩 무력화.

    이 방법의 단점은 다음 첫 번째 쿼리에서 확인 된 개체 원하는 액티브에 당겨 두 번째 쿼리를 실행해야한다는 것입니다 :

    # first query
    idents = Course
        .eager_load(:students)  # eager load for OUTER JOIN
        .where(
            student_enrollments: {student_id: some_user.id, id: nil}, 
            active: true
        )
        .distinct
        .pluck(:id)  # abort eager loading but preserve OUTER JOIN
    
    # second query
    Course.where(id: idents)
    
  11. ==============================

    11.It'a 레일 활성 모델에 쿼리를 가입 할 수 있습니다.

    It'a 레일 활성 모델에 쿼리를 가입 할 수 있습니다.

    활성 모델 쿼리 형식에 대한 자세한 정보를 원하시면 여기를 클릭하십시오.

    @course= Course.joins("LEFT OUTER JOIN StudentEnrollment 
         ON StudentEnrollment .id = Courses.user_id").
         where("StudentEnrollment .id IS NULL AND StudentEnrollment .student_id = 
        <SOME_STUDENT_ID_VALUE> and Courses.active = true").select
    
  12. ==============================

    12.사용 꽤꽥 :

    사용 꽤꽥 :

    Person.joins{articles.inner}
    Person.joins{articles.outer}
    
  13. from https://stackoverflow.com/questions/24358805/left-outer-join-in-rails-4 by cc-by-sa and MIT license