15

私はStudentモデルとモデルを持っていGpaます。Studenthas_many Gpa. 最近作成された gpa レコードのvalue属性に基づいて生徒を並べ替えるにはどうすればよいですか?

注: 作成日に基づいて個々の学生の GPA を並べ替えたくありません。すべての学生を取得し、最新の GPA レコードに基づいて並べ替えたい

class Student < ActiveRecord::Base
  has_many :gpas
end

@students = Student.order(...)
4

10 に答える 10

13

gpa タイムスタンプがupdated_at

Student.joins(:gpas).order('gpas.updated_at DESC').uniq

gpa を持たない生徒を含めるには

#references is rails 4; works in rails 3 without it
Student.includes(:gpas).order('gpas.updated_at DESC').references(:gpas).uniq

distinctそれが作成するのが気に入らない場合uniqは、生のSQLを使用できます

Student.find_by_sql("SELECT students.* FROM students
INNER JOIN gpas ON gpas.student_id = students.id
LEFT OUTER JOIN gpas AS future ON future.student_id = gpas.student_id
  AND future.updated_at > gpas.updated_at
WHERE future.id IS NULL ORDER BY gpas.updated_at DESC")
# or some pretty raw arel
gpa_table = Gpa.arel_table
on = Arel::Nodes::On.new(
  Arel::Nodes::Equality.new(gpa_table[:student_id], Student.arel_table[:id])
)
inner_join = Arel::Nodes::InnerJoin.new(gpa_table, on)
future_gpa_table = Gpa.arel_table.alias("future")
on = Arel::Nodes::On.new(
  Arel::Nodes::Equality.new(future_gpa_table[:student_id], gpa_table[:student_id]).\
  and(future_gpa_table[:updated_at].gt(gpa_table[:updated_at])
  )
)
outer_join = Arel::Nodes::OuterJoin.new(future_gpa_table, on)
# get results
Student.joins(inner_join).joins(outer_join).where("future.id IS NULL").\
order('gpas.updated_at DESC')
于 2013-09-05T15:46:50.323 に答える
4

便利でほとんどがルビーの方法でこれを達成する方法があるかどうかはわかりません。効率的な実装に必要な SQL には、おそらく結合に基づく順序が必要です。

select
  ...
from
  students
order by 
  (  select gpas.value
       from gpas
      where gpas.student_id = student.id
   order by gpas.as_of_date desc
      limit 1)

それがMySQLで合法かどうかはわかりませんが、もしそうなら、おそらく次のことができます:

Student.order("(select gpas.value from gpas where gpas.student_id = student.id order by gpas.as_of_date desc limit 1)")

一方、最後の値が重要なように思われるので、gpas にコールバックを実装して、学生テーブルに「last_gpa_id」または「last_gpa_value」を設定して、この共通結合をより効率的にすることをお勧めします。

もちろん、実装は簡単です。

于 2013-06-18T21:24:51.347 に答える
1

@students = Student.includes(:gpas).order('gpas.value DESC')

それでも、これには を持っていない学生が含まれることに注意することが重要gpasです。しかし、あなたはそれを簡単にフィルタリングすることができます@students.delete_if{ |s| s.gpas.blank? }

于 2013-06-18T21:53:16.027 に答える
0

この方法を試すことができると思います:

class Student < ActiveRecord::Base
  attr_accessible :name
  has_many :gpas

  def self.by_last_gpas
    sql = <<-SQL
      select students.*,
        (
          select gpas.created_at from gpas where student_id=students.id
          order by gpas.created_at desc
          limit 1
        ) as last_created_at
      from students
      order by last_created_at desc
    SQL
    Student.find_by_sql(sql)
  end
end
于 2013-09-11T04:01:14.517 に答える
0

クイックアンドダーティ:

次のようなクエリを実装して、必要な AR オブジェクトを取得できます。

select s.* from students s, gpas g 
  where s.id = gpas.student_id 
  and gpas.id in (select max(id) from gpas group by student_id)
  order by gpas.value

created_at が高いレコードほど id が高いと仮定します。

また

より良い方法:

学生の最後のGPAスコアが頻繁に必要になると思います。:last_gpa_scoreStudent モデルに新しい列を追加してみませんか?

コールバックを使用して、このフィールドの一貫性と自動入力を維持できます。つまり、次のようになります。

class Gpa < ActiveRecord::Base
  belongs_to :student
  after_save :update_student_last_score

  private
    def update_student_last_score
      self.student.update_last_gpa_score
    end
end

class Student < ActiveRecord::Base
  has_many :gpas

  def update_last_gpa_score
    self.last_gpa_score = self.gpas.order("created_at DESC").first.value
  end
end

その後、学生の last_gpa_score フィールドで好きなことを行うことができます。

于 2013-09-11T11:15:06.390 に答える
0

おそらく次のようなもの

Student.joins(:gpas).order("gpas.value DESC")
于 2013-06-18T16:54:57.067 に答える
0

DB に合わせてテーブル名と列名を調整する必要があります。

SELECT s.*, g.*
  FROM (SELECT studentId, MAX(gpaDate) as gpaDate FROM gpas GROUP BY studentId) maxgpa
  JOIN gpas g
    ON g.studentid = maxgpa.studentId
   AND g.gpaDate   = maxgpa.gpaDate
  JOIN students s
    ON s.studentId = g.studentId
 ORDER g.gpaDate DESC
于 2013-09-11T16:29:38.830 に答える
-2

最後に作成された GPA を取得するlast_gpaメソッドを作成し、標準の Ruby ソートを実行します。

def last_gpa
  a.gpas.order(:order=>"created_at DESC").first
end


Student.all.sort { |a, b| a.last_gpa <=> b.last_gpa }
于 2013-09-05T17:55:52.387 に答える