LEFT OUTER, Rails 3'e katılıyor


86

Takip koduna sahibim:

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

bu, tüm gönderileri bulmak ve onları ve ilgili kullanıcıları ve blogları geri getirmek içindir. Ancak, kullanıcılar isteğe bağlıdır, INNER JOINyani :joinsoluşturulan çok sayıda kayıt döndürmez.

LEFT OUTER JOINBunun yerine bir oluşturmak için bunu nasıl kullanırım?


Yanıtlar:


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

3
Ya sadece kullanıcısı olmayan Gönderileri isteseydiniz?
mcr

24
@mcr@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
Linus Oleander

1
Seçimin bir parametreye ihtiyacı yok mu? Bu olması gerekmiyor select('posts.*')mu?
Kevin Sylvestre

Rails 3'te, birleşimleriniz üzerinde gerçek kontrole sahip olmanın ve neler olup bittiğini tam olarak bilmenin tek yolu budur.
Joshua Pinter

75

Bunu includes , Rails kılavuzunda belirtildiği gibi yapabilirsiniz :

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

Sonuçlar:

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)

14
Testlerimden includesbir birleştirme değil, ilişkilendirmeyi almak için ayrı bir sorgu. Bu nedenle N + 1'den kaçınır, ancak kayıtların tek bir sorguda getirildiği JOIN ile aynı şekilde değildir.
Kris,

7
@Kris Bir şekilde haklısın. Dikkat etmeniz gereken bir şey çünkü includesişlev, onu kullandığınız bağlama bağlı olarak her ikisini de yapıyor. Rails kılavuzu, 12. bölümün tamamını okursanız yapabileceğimden daha iyi açıklıyor: guides.rubyonrails.org/ …
WuTangTan

4
Bunun nedeni kısmen soruya cevap verir includesyerine 2 sorguları üretecektir JOINiçin bir ihtiyaç yoksa WHERE.
Rodrigue

14
Siz de eklemediğiniz sürece bu, Rails 4'te bir uyarı oluşturacaktır references(:comments). Ek olarak, bu, döndürülen tüm yorumların includes, muhtemelen istediğiniz gibi olmaması nedeniyle belleğe yüklenmesine neden olur .
Derek,

2
Bu daha da "Railsy" yapmak için: Post.includes(:comments).where(comments: {visible: true}). Bu şekilde kullanmanıza da gerek kalmaz references.
michael

11

Squeel geminin büyük bir hayranıyım :

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

Hem destekler innerve outerpolimorfik belongs_to ilişkileri için bir sınıf / türünü belirtmek için yeteneği, hem de katılır.


10

Kullanım eager_load:

@posts = Post.eager_load(:user)

8

Varsayılan olarak ActiveRecord::Base#joinsadlandırılmış bir ilişkilendirmeyi geçtiğinizde , bir INNER JOIN gerçekleştirecektir. LEFT OUTER JOIN'inizi temsil eden bir dize geçirmeniz gerekecek.

Gönderen belgeler :

:joins- Ya " LEFT JOIN comments ON comments.post_id = id" gibi ek birleştirmeler için bir SQL parçası (nadiren gereklidir), :includeseçenek için kullanılanla aynı biçimde adlandırılmış ilişkilendirmeler , ilişkili tablo (lar) da bir INNER JOIN gerçekleştirecek veya her iki dizenin bir karışımını içeren bir dizi ve adlandırılmış dernekler.

Değer bir dizeyse, tablo sütunlarına karşılık gelmeyen özniteliklere sahip olacağından kayıtlar salt okunur olarak döndürülür. :readonly => falseGeçersiz kılmak için geçiş yapın.


7

Bir yoktur left_outer_joins ActiveRecord yöntem. Bunu şu şekilde kullanabilirsiniz:

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

1
Bu, posterin istediği Rails 3'te yok gibi görünüyor.
cesoid

Doğru; bu, Rails 5.0.0'da tanıtıldı.
Ollie Bennett

4

İyi haber, Rails 5 artık destekliyor LEFT OUTER JOIN. Sorgunuz artık şöyle görünecektir:

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

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")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.