【问题标题】:Ruby on Rails Active Record QueryRuby on Rails 活动记录查询
【发布时间】:2015-09-18 04:07:58
【问题描述】:

雇主和工作。雇主有很多工作。作业有一个布尔字段开始。

我正在尝试查询并查找拥有多个已开始工作的雇主的数量。

我该怎么做?

Employer.first.jobs.where(started: true).count

我是使用带计数器的循环还是有办法通过查询来做到这一点?

谢谢!

【问题讨论】:

  • 你可以为你的问题增加标题吗?

标签: ruby-on-rails ruby activerecord model


【解决方案1】:

你可以有条件加入

Employer.joins(:jobs).where(jobs: {started: true}).count

【讨论】:

  • 我也试过了,它还计算了出于某种原因开始的总作业数。 IE。结果与 Job.where(start: true).count 相同。知道为什么吗?
  • 您确定您有多个工作分配给一名员工吗?
  • 是的。我有 4 个雇主。所以 Employer.joins(:jobs).count 应该是 4 对吧?但它实际上给了我工作的数量。我很困惑
  • 这是一个很好的答案,特别是因为它很容易成为:with_active_jobs 的范围。我总是发现在制作自定义方法之前最好使用范围等。 Rails 有能力
【解决方案2】:

您可以在 Employer 模型中创建这样的范围:

def self.with_started_job
  joins(:jobs)
    .where(jobs: { started: true })
    .having('COUNT(jobs.id) > 0')
end

然后,要获取已开始工作的雇主数量,您只需使用Employer.with_started_job.count

【讨论】:

  • 我试过这个,它给出了出于某种原因开始的总作业的计数。 IE。结果与 Job.where(start: true).count 相同。我已经将您的代码复制到模型中。知道为什么吗?
【解决方案3】:

缺少的是 group by 子句。使用.group(),然后使用count。像

Employer.select("employers.id,count(*)").joins(:jobs).where("jobs.started = 1").group("employers.id")

查询连接两个表,消除错误记录,然后计算每个employee.id 组合在一起时的总记录数。

【讨论】:

    【解决方案4】:

    探索性编程的时间到了!

    鉴于我不太了解 SQL,我这样做的方式可能不是最佳的。如果不使用子查询,我就无法使用两个聚合。所以我把任务一分为二:

    • 获取所有开始了不止一项工作的雇主
    • 统计结果集中的条目数

    当然都是数据库级别的!并且没有原始 SQL,所以在这里和那里使用 Arel。这是我想出的:

    class Employer < ActiveRecord::Base
      has_many :jobs
    
      # I explored my possibilities using this method: fetches
      # all the employers and number of jobs each has started.
      # Looks best> Employer.with_started_job_counts.map(&:attributes)
      # In the final method this one is not used, it's just handy.
      def self.with_started_job_counts
        jobs = Job.arel_table
        joins(:jobs).select(arel_table[Arel.star],
                            jobs[:id].count.as('job_count'))
          .merge(Job.where(started: true))
          .group(:id)
      end
    
      # Alright. Now try to apply it. Seems to work alright.
      def self.busy
        jobs = Job.arel_table
    
        joins(:jobs).merge(Job.where(started: true))
                    .group(:id)
                    .having(jobs[:id].count.gt 1)
      end
    
      # This is one of the tricks I've learned while fiddling
      # with Arel. Counts any relations on the database level.
      def self.generic_count(subquery)
        from(subquery).count
      end
    
      # So now... we get this.
      def self.busy_count
        generic_count(busy)
      end
      # ...and it seems to get what we need!
    end
    

    生成的 SQL...很大。不是很大,但您可能必须用它解决性能问题。

    SELECT COUNT(*)
    FROM (
      SELECT "employers".*
      FROM "employers"
        INNER JOIN "jobs" ON "jobs"."employer_id" = "employers"."id"
      WHERE "jobs"."started" = ?
      GROUP BY "employers"."id"
      HAVING COUNT("jobs"."id") > 1
    ) subquery  [["started", "t"]]
    

    ...不过,它似乎得到了结果。

    【讨论】:

      猜你喜欢
      • 2012-12-18
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 1970-01-01
      • 2016-05-24
      相关资源
      最近更新 更多