LEFT OUTER schließt sich Rails 3 an


85

Ich habe folgenden Code:

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

Dies soll alle Beiträge finden und sie sowie die zugehörigen Benutzer und Blogs zurückgeben. Jedoch Benutzer sind optional , was bedeutet , dass die , INNER JOINdie :joinsnicht zurückkehr viele Datensätze erzeugt.

Wie verwende ich dies, um LEFT OUTER JOINstattdessen eine zu generieren ?


Antworten:


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

3
Was wäre, wenn Sie nur die Beiträge wollten, die keinen Benutzer hatten?
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
Benötigen Sie keinen Parameter? Sollte das nicht sein select('posts.*')?
Kevin Sylvestre

In Rails 3 ist dies die einzige Möglichkeit, Ihre Joins wirklich zu kontrollieren und genau zu wissen, was los ist.
Joshua Pinter

75

Sie können dies tun, includes wie im Rails-Handbuch dokumentiert :

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

Ergebnisse 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)

14
Aus meinen Tests includesgeht kein Join hervor, sondern eine separate Abfrage, um die Zuordnung zu erhalten. So wird N + 1 vermieden, jedoch nicht auf die gleiche Weise wie bei einem JOIN, bei dem die Datensätze in einer Abfrage abgerufen werden.
Kris

7
@Kris Du hast in gewisser Weise recht. Dies ist etwas includes, auf das Sie achten
WuTangTan

4
Dies beantwortet die Frage nur teilweise, da includes2 Abfragen anstelle von a generiert werden, JOINwenn Sie keine benötigen WHERE.
Rodrigue

14
Dies generiert eine Warnung in Rails 4, sofern Sie nicht auch hinzufügen references(:comments). Darüber hinaus führt dies dazu, dass alle zurückgegebenen Kommentare aufgrund von includes, was möglicherweise nicht das ist, was Sie möchten , eifrig in den Speicher geladen werden .
Derek Prior

2
Um dies noch "Railsy" zu machen : Post.includes(:comments).where(comments: {visible: true}). Auf diese Weise müssen Sie auch nicht verwenden references.
Michael

11

Ich bin ein großer Fan des Squeel-Edelsteins :

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

Es unterstützt sowohl innerund outerverbindet, sowie die Fähigkeit , eine Klasse / Typ für polymorphe belongs_to Beziehungen zu spezifizieren.


10

Verwendung eager_load:

@posts = Post.eager_load(:user)

8

Wenn Sie ActiveRecord::Base#joinseine benannte Zuordnung übergeben, wird standardmäßig eine INNERE VERBINDUNG ausgeführt. Sie müssen eine Zeichenfolge übergeben, die Ihren LEFT OUTER JOIN darstellt.

Aus der Dokumentation :

:joins- Entweder ein SQL-Fragment für zusätzliche LEFT JOIN comments ON comments.post_id = idVerknüpfungen wie " " (selten erforderlich), benannte Zuordnungen in derselben Form, die für die :includeOption verwendet wird, die einen INNER JOIN für die zugehörigen Tabellen ausführt, oder ein Array, das eine Mischung aus beiden Zeichenfolgen enthält und benannte Assoziationen.

Wenn der Wert eine Zeichenfolge ist, werden die Datensätze schreibgeschützt zurückgegeben, da sie Attribute haben, die nicht den Spalten der Tabelle entsprechen. Übergeben, um :readonly => falsezu überschreiben.


7

In activerecord befindet sich eine left_outer_joins- Methode. Sie können es so verwenden:

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

1
Dies scheint in Rails 3 nicht zu existieren, was das Poster verlangt.
Cesoid

Richtig; Dies wurde in Rails 5.0.0 eingeführt.
Ollie Bennett

4

Gute Nachrichten, Rails 5 unterstützt jetzt LEFT OUTER JOIN. Ihre Anfrage würde nun folgendermaßen aussehen:

@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")
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.