Mam następujący kod:
@posts = Post.joins(:user).joins(:blog).select
co ma na celu znalezienie wszystkich postów i zwrócenie ich oraz powiązanych użytkowników i blogów. Jednak użytkownicy są opcjonalni, co oznacza, że to, INNER JOIN
co :joins
generuje, nie zwraca wielu rekordów.
Jak użyć tego do wygenerowania LEFT OUTER JOIN
zamiast tego?
ruby-on-rails
ruby
activerecord
Neil Middleton
źródło
źródło
Odpowiedzi:
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id"). joins(:blog).select
źródło
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
select('posts.*')
?Możesz to zrobić
includes
zgodnie z opisem w przewodniku po Railsach :Post.includes(:comments).where(comments: {visible: true})
Prowadzi do:
SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1)
źródło
includes
nie robi złączenia, ale osobne zapytanie, aby uzyskać skojarzenie. Więc unika N + 1, ale nie w taki sam sposób, jak JOIN, w którym rekordy są pobierane w jednym zapytaniu.includes
funkcja robi jedno i drugie, w zależności od kontekstu, w którym jej używasz. Przewodnik po Railsach wyjaśnia to lepiej niż ja, gdybym przeczytał całą sekcję 12: Guides.rubyonrails.org/ …includes
wygeneruje 2 zapytania zamiast jednego,JOIN
jeśli nie potrzebujeszWHERE
.references(:comments)
. Dodatkowo spowoduje to, że wszystkie zwrócone komentarze będą chętnie ładowane do pamięci z powoduincludes
, co prawdopodobnie nie jest tym, czego chcesz.Post.includes(:comments).where(comments: {visible: true})
. W ten sposób nie musisz też używaćreferences
.Jestem wielkim fanem piskląt :
Obsługuje zarówno połączenia, jak
inner
iouter
łączenia, a także możliwość określenia klasy / typu dla polimorficznych relacji przynależności_do.źródło
Zastosowanie
eager_load
:@posts = Post.eager_load(:user)
źródło
Domyślnie po przekazaniu
ActiveRecord::Base#joins
nazwanego powiązania wykona INNER JOIN. Będziesz musiał przekazać ciąg reprezentujący LEWE ZEWNĘTRZNE POŁĄCZENIE.Z dokumentacji :
źródło
W activerecord istnieje metoda left_outer_joins. Możesz go używać w ten sposób:
@posts = Post.left_outer_joins(:user).joins(:blog).select
źródło
Dobra wiadomość, Rails 5 obsługuje teraz
LEFT OUTER JOIN
. Twoje zapytanie wyglądałoby teraz następująco:@posts = Post.left_outer_joins(:user, :blog)
źródło
class User < ActiveRecord::Base has_many :friends, :foreign_key=>"u_from",:class_name=>"Friend" end class Friend < ActiveRecord::Base belongs_to :user end friends = user.friends.where(:u_req_status=>2).joins("LEFT OUTER JOIN users ON users.u_id = friends.u_to").select("friend_id,u_from,u_to,u_first_name,u_last_name,u_email,u_fbid,u_twtid,u_picture_url,u_quote")
źródło