[RUBY-ON-RAILS] 액티브 쿼리 연합
RUBY-ON-RAILS액티브 쿼리 연합
나는 레일의 쿼리 인터페이스에 루비 (적어도 나에게) 복잡한 쿼리의 몇 가지를 작성했습니다 :
watched_news_posts = Post.joins(:news => :watched).where(:watched => {:user_id => id})
watched_topic_posts = Post.joins(:post_topic_relationships => {:topic => :watched}).where(:watched => {:user_id => id})
이러한 쿼리는 모두 스스로 잘 작동합니다. 모두 반환 포스트 객체. 나는 하나의 ActiveRelation에이 게시물을 결합하고 싶습니다. 어떤 시점에서 수백 게시물의 수천이있을 수 있기 때문에,이 요구 사항은 데이터베이스 수준에서 수행 할 수 있습니다. 그것은 MySQL의 쿼리가 있다면, 나는 사용자 UNION 연산자를 간단하게 할 수있다. 내가 RoR에의 쿼리 인터페이스와 비슷한 할 수 있다면 사람은 알고 있나요?
해결법
-
==============================
1.여기에 UNION 여러 범위로 할 수 있습니다 내가 쓴 빠른 작은 모듈입니다. 또한 액티브 :: 관계의 인스턴스로 결과를 반환합니다.
여기에 UNION 여러 범위로 할 수 있습니다 내가 쓴 빠른 작은 모듈입니다. 또한 액티브 :: 관계의 인스턴스로 결과를 반환합니다.
module ActiveRecord::UnionScope def self.included(base) base.send :extend, ClassMethods end module ClassMethods def union_scope(*scopes) id_column = "#{table_name}.id" sub_query = scopes.map { |s| s.select(id_column).to_sql }.join(" UNION ") where "#{id_column} IN (#{sub_query})" end end end
여기서 요지는 다음과 같습니다 https://gist.github.com/tlowrimore/5162327
요청으로, 여기 UnionScope 작동하는 방법의 예입니다 :
class Property < ActiveRecord::Base include ActiveRecord::UnionScope # some silly, contrived scopes scope :active_nearby, -> { where(active: true).where('distance <= 25') } scope :inactive_distant, -> { where(active: false).where('distance >= 200') } # A union of the aforementioned scopes scope :active_near_and_inactive_distant, -> { union_scope(active_nearby, inactive_distant) } end
-
==============================
2.나는이 문제가 발생했고, 지금 내 이동 - 투 전략 (손이나 기존 범위에 to_sql를 사용하여) SQL을 생성하고 다음 절에서 그것을 충실하는 것입니다. 나는 그것이 더 효율적으로 귀하의 승인 된 방법보다입니다 보장 할 수 있지만, 눈에 상대적으로 쉽게 당신에게 정상적인 ARel 객체 등을 제공합니다.
나는이 문제가 발생했고, 지금 내 이동 - 투 전략 (손이나 기존 범위에 to_sql를 사용하여) SQL을 생성하고 다음 절에서 그것을 충실하는 것입니다. 나는 그것이 더 효율적으로 귀하의 승인 된 방법보다입니다 보장 할 수 있지만, 눈에 상대적으로 쉽게 당신에게 정상적인 ARel 객체 등을 제공합니다.
watched_news_posts = Post.joins(:news => :watched).where(:watched => {:user_id => id}) watched_topic_posts = Post.joins(:post_topic_relationships => {:topic => :watched}).where(:watched => {:user_id => id}) Post.from("(#{watched_news_posts.to_sql} UNION #{watched_topic_posts.to_sql}) AS posts")
당신은뿐만 아니라 두 개의 서로 다른 모델이 작업을 수행 할 수 있습니다,하지만 당신은 확인해야 그들이 모두 UNION 내부 "같은 모양"- 당신이 있는지가 같은 열을 생산할 예정 만들기 위해 두 쿼리에서 선택한 사용할 수 있습니다.
topics = Topic.select('user_id AS author_id, description AS body, created_at') comments = Comment.select('author_id, body, created_at') Comment.from("(#{comments.to_sql} UNION #{topics.to_sql}) AS comments")
-
==============================
3.올리브 '답변에 따라, 나는이 문제에 다른 해결책을 마련했다. 그것은 해킹과 같은 약간의 비트를 느낀다,하지만 내가 처음에 후 무엇이다 ActiveRelation의 인스턴스를 반환합니다.
올리브 '답변에 따라, 나는이 문제에 다른 해결책을 마련했다. 그것은 해킹과 같은 약간의 비트를 느낀다,하지만 내가 처음에 후 무엇이다 ActiveRelation의 인스턴스를 반환합니다.
Post.where('posts.id IN ( SELECT post_topic_relationships.post_id FROM post_topic_relationships INNER JOIN "watched" ON "watched"."watched_item_id" = "post_topic_relationships"."topic_id" AND "watched"."watched_item_type" = "Topic" WHERE "watched"."user_id" = ? ) OR posts.id IN ( SELECT "posts"."id" FROM "posts" INNER JOIN "news" ON "news"."id" = "posts"."news_id" INNER JOIN "watched" ON "watched"."watched_item_id" = "news"."id" AND "watched"."watched_item_type" = "News" WHERE "watched"."user_id" = ? )', id, id)
사람이 본질적으로 세 개의 쿼리를 실행 있기 때문에,이를 최적화하거나 성능을 개선하기 위해 어떤 제안을 가지고 있으며, 약간의 중복을 느끼면 나는 아직도 그것을 감사하겠습니다.
-
==============================
4.방법에 대한 ...
방법에 대한 ...
def union(scope1, scope2) ids = scope1.pluck(:id) + scope2.pluck(:id) where(id: ids.uniq) end
-
==============================
5.또한 범위에 대한 노조 방법 액티브을 확장 브라이언 헴펠의 active_record_union 보석을 사용할 수 있습니다.
또한 범위에 대한 노조 방법 액티브을 확장 브라이언 헴펠의 active_record_union 보석을 사용할 수 있습니다.
귀하의 질의는 다음과 같이 될 것이다 :
Post.joins(:news => :watched). where(:watched => {:user_id => id}). union(Post.joins(:post_topic_relationships => {:topic => :watched} .where(:watched => {:user_id => id}))
희망이 결국 언젠가는 액티브로 통합됩니다.
-
==============================
6.당신은을 사용하여 OR 대신에 UNION의 수 있을까요?
당신은을 사용하여 OR 대신에 UNION의 수 있을까요?
그럼 당신은 뭔가를 같이 할 수있는 :
Post.joins(:news => :watched, :post_topic_relationships => {:topic => :watched}) .where("watched.user_id = :id OR topic_watched.user_id = :id", :id => id)
(당신이 있기 때문에 내가 너무 확실 테이블의 이름은 쿼리 일 무슨 아니에요 두 번 감시 테이블을 조인)
조인이 많이 있기 때문에, 그것은 또한 데이터베이스에 매우 무거운 수도 있지만 최적화 할 수 있습니다.
-
==============================
7.틀림없이, 이것은 가독성을 향상 시키지만, 반드시 성능 :
틀림없이, 이것은 가독성을 향상 시키지만, 반드시 성능 :
def my_posts Post.where <<-SQL, self.id, self.id posts.id IN (SELECT post_topic_relationships.post_id FROM post_topic_relationships INNER JOIN watched ON watched.watched_item_id = post_topic_relationships.topic_id AND watched.watched_item_type = "Topic" AND watched.user_id = ? UNION SELECT posts.id FROM posts INNER JOIN news ON news.id = posts.news_id INNER JOIN watched ON watched.watched_item_id = news.id AND watched.watched_item_type = "News" AND watched.user_id = ?) SQL end
이 같이 호출 할 수 있도록이 방법은 액티브 :: 관계를 반환합니다 :
my_posts.order("watched_item_type, post.id DESC")
-
==============================
8.active_record_union 보석이있다. 도움이 될 수
active_record_union 보석이있다. 도움이 될 수
https://github.com/brianhempel/active_record_union
"게시물"을 선택합니다. * FROM ( "게시물"을 선택합니다. * "게시물", "게시물"FROM. "USER_ID"= 1 노동 조합 "게시물"SELECT * "게시물"FROM WHERE (published_at < '2014년 7월 19일 16 : 04 : 21.918366'). ) 게시물
-
==============================
9.난 그냥 반환되는 레코드의 배열을 당신이 필요로하는 두 개의 쿼리를 실행하고 결합 할 것이다 :
난 그냥 반환되는 레코드의 배열을 당신이 필요로하는 두 개의 쿼리를 실행하고 결합 할 것이다 :
@posts = watched_news_posts + watched_topics_posts
또는, 적어도 시험이 아웃시. 당신은 루비의 배열의 조합이 너무 느린 것입니다 생각하십니까? 이 문제를 해결하기 위해 제안 된 쿼리를 보면, 나는 성능 차이의 의미가있을 것이라고 확신하고 있지 않다.
-
==============================
10.비슷한 경우 내가 두 배열을 합산 미나리를 사용 : paginate_array를 (). 아주 좋은 솔루션을 작업. 내가 같은 테이블에 다른 순서 () 두 개의 결과를 요약해야하기 때문에 나는) 여기서 (사용 할 수 없습니다.
비슷한 경우 내가 두 배열을 합산 미나리를 사용 : paginate_array를 (). 아주 좋은 솔루션을 작업. 내가 같은 테이블에 다른 순서 () 두 개의 결과를 요약해야하기 때문에 나는) 여기서 (사용 할 수 없습니다.
-
==============================
11.엘리엇 넬슨은 관계의 일부가 비어있는 경우를 제외하고, 좋은 대답했다. 나는 그런 일을 할 것입니다 :
엘리엇 넬슨은 관계의 일부가 비어있는 경우를 제외하고, 좋은 대답했다. 나는 그런 일을 할 것입니다 :
def union_2_relations(relation1,relation2) sql = "" if relation1.any? && relation2.any? sql = "(#{relation1.to_sql}) UNION (#{relation2.to_sql}) as #{relation1.klass.table_name}" elsif relation1.any? sql = relation1.to_sql elsif relation2.any? sql = relation2.to_sql end relation1.klass.from(sql)
종료
-
==============================
12.내가 레일 응용 프로그램에 대한 내 자신의 루비에 UNION을 사용하여 SQL 쿼리를 결합하는 방법을 Heres.
내가 레일 응용 프로그램에 대한 내 자신의 루비에 UNION을 사용하여 SQL 쿼리를 결합하는 방법을 Heres.
당신은 당신의 자신의 코드에 영감을 아래 사용할 수 있습니다.
class Preference < ApplicationRecord scope :for, ->(object) { where(preferenceable: object) } end
아래는 내가 함께 범위에 합류 UNION입니다.
def zone_preferences zone = Zone.find params[:zone_id] zone_sql = Preference.for(zone).to_sql region_sql = Preference.for(zone.region).to_sql operator_sql = Preference.for(Operator.current).to_sql Preference.from("(#{zone_sql} UNION #{region_sql} UNION #{operator_sql}) AS preferences") end
-
==============================
13.적은 문제를 쉽게 따를 :
적은 문제를 쉽게 따를 :
def union_scope(*scopes) scopes[1..-1].inject(where(id: scopes.first)) { |all, scope| all.or(where(id: scope)) } end
그래서 결국 :
union_scope(watched_news_posts, watched_topic_posts)
from https://stackoverflow.com/questions/6686920/activerecord-query-union by cc-by-sa and MIT license
'RUBY-ON-RAILS' 카테고리의 다른 글
[RUBY-ON-RAILS] 로그인 후 유증 리디렉션 실패 (0) | 2020.02.05 |
---|---|
[RUBY-ON-RAILS] 액티브 또는 쿼리 해시 표기 (0) | 2020.02.05 |
[RUBY-ON-RAILS] 어떻게 레일에서 같은 양식 버튼을 제출 여러 만듭니 까? (0) | 2020.02.05 |
[RUBY-ON-RAILS] 3 레일 : "필드 - 오류가있는"페이지의 모양이 변경 래퍼. 어떻게 이것을 피하기 위해? (0) | 2020.02.05 |
[RUBY-ON-RAILS] accepts_nested_attributes_for find_or_create와? (0) | 2020.02.05 |