2010-07-14 16 views
85

Ho il seguente codice:LEFT OUTER si unisce in Rails 3

@posts = Post.joins(:user).joins(:blog).select 

che ha lo scopo di trovare tutti i messaggi e li e gli utenti associati e blog tornare. Tuttavia, gli utenti sono facoltativi, il che significa che lo :joins generato da :joins non restituisce molti record.

Come utilizzare questo per generare un LEFT OUTER JOIN?

+0

Vedi anche [LEFT OUTER JOIN in Rails 4] (http://stackoverflow.com/questions/24358805/left-outer-join-in-rails-4/35363012) – Yarin

risposta

110
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id"). 
       joins(:blog).select 
+3

e se volessi solo i messaggi che non avevano utenti? – mcr

+24

@mcr '@posts = Post.joins (" LEFT OUTER JOIN utenti ON users.id = posts.user_id "). Join (: blog) .where (" users.id IS NULL "). Select' – Oleander

+1

Does not seleziona bisogno di un param?Non dovrebbe essere 'select ('posts. *')'? –

8

Per impostazione predefinita, quando si passa a ActiveRecord::Base#joins un'associazione denominata, verrà eseguito un INTERNO INTERNO. Dovrai passare una stringa che rappresenta il TUO ESTERNO SINISTRO.

Da the documentation:

:joins - O un frammento di SQL per ulteriori unisce come "LEFT JOIN comments ON comments.post_id = id" (raramente necessario), denominate associazioni nella stessa forma utilizzata per l'opzione :include, che eseguirà un INNER JOIN sulla tabella o sulle tabelle associate o una matrice contenente una combinazione di stringhe e associazioni denominate.

Se il valore è una stringa , i record verranno restituiti in sola lettura poiché avranno attributi che non corrispondono alle colonne della tabella. Passa a :readonly => false per eseguire l'override.

73

Si può fare con questo con includesas documented in the Rails guide:

Post.includes(:comments).where(comments: {visible: true}) 

risultati in:

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) 
+4

Questo è il modo corretto "Rails". – ricsrock

+13

Dai miei test 'includes' non fa un join, ma una query separata per ottenere l'assosiation. Evita quindi N + 1, ma non allo stesso modo di un JOIN in cui i record vengono recuperati in una query. – Kris

+6

@ Kris Hai ragione, in un certo senso. È qualcosa a cui devi prestare attenzione perché la funzione 'include' fa entrambe le cose, a seconda del contesto in cui la stai usando. La guida di Rails lo spiega meglio di me se leggi tutta la sezione 12: http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations – WuTangTan

11

Sono un grande fan del squeel gem:

Post.joins{user.outer}.joins{blog} 

Supporta sia i join inner e outer, sia la possibilità di specificare una classe/tipo per le relazioni polymorphic belongs_to.

+0

Qual è stato il downvote per? – plainjimbo

+1

Penso che sia stato un principio downvoter =) –

0
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") 
10

Uso eager_load:

@posts = Post.eager_load(:user) 
6

C'è un metodo left_outer_joins in ActiveRecord. Si può usare in questo modo:

@posts = Post.left_outer_joins(:user).joins(:blog).select 
+1

Questo non sembra esistere in Rails 3, che è ciò che il poster sta chiedendo. – cesoid

+0

corretto; questo è stato introdotto in Rails 5.0.0. –

4

Buone notizie, Rails 5 ora supporta LEFT OUTER JOIN. La query potrebbe apparire come:

@posts = Post.left_outer_joins(:user, :blog)