【问题标题】:How to use rails ActiveRecord to perform a left join of a Model with a subquery如何使用 Rails ActiveRecord 执行带有子查询的模型的左连接
【发布时间】:2018-04-26 11:07:42
【问题描述】:

我正在使用 rails 5。当我在 rails 控制台中执行以下直接 SQL 查询时,我得到以下预期结果:

    2.3.5 :053 >   w = ActiveRecord::Base.connection.exec_query("SELECT * FROM students s LEFT JOIN (SELECT student_id, MAX(urgent) AS has_urgent,MAX(created_at) AS last_contact FROM reports GROUP BY student_id) r ON r.student_id = s.id")
   (0.5ms)  SELECT * FROM students s LEFT JOIN (SELECT student_id, MAX(urgent) AS has_urgent,MAX(created_at) AS last_contact FROM reports GROUP BY student_id) r ON r.student_id = s.id
 => #<ActiveRecord::Result:0x00000000051e1518 @columns=["id", "name", "cwid", "email", "phone", "company", "role", "advisor", "advisor_email", "mentor", "created_at", "updated_at", "student_id", "has_urgent", "last_contact"], @rows=[[1, "Johnny Smith", "71419940", "jsmith@gmail.com", "8435550001", "foxtrot", "mentor", "John I. Moore, Jr.", "john.moore@citadel.edu", "", "2017-11-13 14:58:50.128114", "2017-11-13 14:58:50.128168", nil, nil, nil], [2, "Shelly", "12345678", "shelly@gmail.com", "8435550002", "bravo", "mentee", "Michael P. Verdicchio", "mv@citadel.edu", "Johnny Smith", "2017-11-13 14:58:50.160195", "2017-11-13 14:58:50.160243", "2", "t", "2017-11-13 14:58:50.210105"], [3, "Max", "87654321", "max@gmail.com", "8435550003", "palmetto", "unassigned", "Mei-Qin Chen", "mei.chen@citadel.edu", "", "2017-11-13 14:58:50.179220", "2017-11-13 14:58:50.179258", nil, nil, nil], [4, "George", "87654325", "george@gmail.com", "8435550004", "palmetto", "mentee", "Deepti Joshi", "djoshi@citadel.edu", "Johnny Smith", "2017-11-13 14:58:50.189733", "2017-11-13 14:58:50.189762", "4", "f", "2017-11-03 14:58:50.260914"]], @hash_rows=nil, @column_types={}> 

但是,这会返回一个 ActiveRecord::Result 类型,但我真正想要的是使用 Rails ActiveRecord 执行相同的查询,但返回一个 ActiveRecord::Relation,我是这样想的:

2.3.5 :054 > w = Student.joins("LEFT JOIN (SELECT student_id, MAX(urgent) AS has_urgent,MAX(created_at) AS last_contact FROM reports GROUP BY student_id) r ON r.student_id = students.id")
  Student Load (0.5ms)  SELECT  "students".* FROM "students" LEFT JOIN (SELECT student_id, MAX(urgent) AS has_urgent,MAX(created_at) AS last_contact FROM reports GROUP BY student_id) r ON r.student_id = students.id LIMIT ?  [["LIMIT", 11]]
 => #<ActiveRecord::Relation [#<Student id: 1, name: "Johnny Smith", cwid: "71419940", email: "jsmith@gmail.com", phone: "8435550001", company: "foxtrot", role: "mentor", advisor: "John I. Moore, Jr.", advisor_email: "john.moore@citadel.edu", mentor: "", created_at: "2017-11-13 14:58:50", updated_at: "2017-11-13 14:58:50">, #<Student id: 2, name: "Shelly", cwid: "12345678", email: "shelly@gmail.com", phone: "8435550002", company: "bravo", role: "mentee", advisor: "Michael P. Verdicchio", advisor_email: "mv@citadel.edu", mentor: "Johnny Smith", created_at: "2017-11-13 14:58:50", updated_at: "2017-11-13 14:58:50">, #<Student id: 3, name: "Max", cwid: "87654321", email: "max@gmail.com", phone: "8435550003", company: "palmetto", role: "unassigned", advisor: "Mei-Qin Chen", advisor_email: "mei.chen@citadel.edu", mentor: "", created_at: "2017-11-13 14:58:50", updated_at: "2017-11-13 14:58:50">, #<Student id: 4, name: "George", cwid: "87654325", email: "george@gmail.com", phone: "8435550004", company: "palmetto", role: "mentee", advisor: "Deepti Joshi", advisor_email: "djoshi@citadel.edu", mentor: "Johnny Smith", created_at: "2017-11-13 14:58:50", updated_at: "2017-11-13 14:58:50">]> 

对于第二种方法,Right 表列不会出现在结果中,即使生成的 SQL 看起来非常相似。我是 Rails 和 ActiveRecord 的新手,所以如果有人可以帮助我理解为什么这两个结果不同,以及我应该怎么做才能使第二个 ActiveRecord 查询像直接 SQL 查询一样工作,我将不胜感激。

【问题讨论】:

    标签: ruby-on-rails rails-activerecord


    【解决方案1】:

    如果您使用的是 rails 5,请使用 left_joins or left_outer_joins。 试试这个,让我知道它是否适合你。

    Student.left_outer_joins(:reports).select("student.*, MAX(urgent) AS has_urgent,MAX(created_at) AS last_contact").group("student.id").


    如果您想采用第一种方法,那么这些方法可能对您有所帮助。

    1. result.columns #获取结果的列名。
    2. result.rows #获取结果的记录值。
    3. result.to_hash #获取代表结果的哈希数组(列=>值)
    4. #ActiveRecord::Result also includes Enumerable

    【讨论】:

    • 我遇到的问题是来自内部选择的列没有出现在结果中。作为新手,我只是假设连接的结果会暴露连接中左右表的所有列。我最后不得不在最后加上一个 .select('*,r.has_urgent,r.last_contact') 才能让它们出现在结果中。不确定这是否是必要的,但它确实有效。
    猜你喜欢
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-10
    • 2012-12-03
    相关资源
    最近更新 更多