【问题标题】:rails. select records with max()铁轨。使用 max() 选择记录
【发布时间】:2018-03-24 23:40:27
【问题描述】:

我有一个这样的表,我想返回薪水最高的前两个人(按姓名),以及对应薪水的记录。这是表格

id, name, salary
1, Tom, 200
2, Tom, 300
3, Bob, 400
4, Bob, 500
5, Alice, 600
6, Alice, 700

我用过这个命令

Employer.select("employers.*, max(employers.salary) as maxsalary").group("employers.name").order("maxsalary desc").limit(2)

期望回报:

id, name, salary
6, Alice, 700
4, Bob, 500

我得到的似乎是这样的:

id, name, salary
5, Alice, 600
3, Bob, 400

是否有选择响应 max 的记录?非常感谢任何评论/答案。

【问题讨论】:

    标签: sql ruby-on-rails activerecord


    【解决方案1】:

    这个问题实际上非常棘手! 这似乎很容易,但事实并非如此。

    查询:

    Employer.joins(%Q|
      LEFT JOIN employers as e 
      ON 
      e.name = employers.name 
      AND 
      employers.salary < e.salary
    |).where('e.salary IS NULL').order('employers.salary DESC').limit(2)
    

    这是怎么工作的!(我去过那里)

    我们要确保每个雇主只获得最高的工资,然后获得其中最高的 2 个。


    一些理论知识(如果您只想了解查询,请跳过此部分)

    让 Salary 是一个函数 S(name,id),它返回一个给定 name 和 id 的值 为了证明给定的薪水 (S(name,id)) 是最高的,我们必须证明 我们想证明

    • ∀x S(name,id) > S(name,x)(这个薪水高于其他所有 这个名字的薪水)

    • ¬∃x S(name, id)

    第一种方法需要我们获取我不太喜欢的那个名字的所有记录。

    第二个需要一种聪明的方式来说明没有比这个更高的记录。


    返回 SQL

    如果我们离开联接表时,姓名和薪水小于联接表:

    %Q|
          LEFT JOIN employers as e 
          ON 
          e.name = employers.name 
          AND 
          employers.salary < e.salary
        |
    

    我们确保所有具有另一个更高薪水记录的记录都将加入同一用户:

    employers.id, employers.name, employers.salary, e.id, e.name, e.salary
    1           , Tom           , 200             , 2   , Tom   , 300
    2           , Tom           , 300
    3           , Bob           , 400             , 4   , Bob   , 500
    4           , Bob           , 500
    5           , Alice         , 600             , 6   , Alice   , 700
    6           , Alice         , 700
    

    这将帮助我们过滤每个雇主的最高薪水,无需分组:

    where('e.salary IS NULL')
    
    employers.id, employers.name, employers.salary, e.id, e.name, e.salary
    2           , Tom           , 300
    4           , Bob           , 500
    6           , Alice         , 700
    

    现在我们要做的就是排序:

    order('employers.salary DESC')
    
    employers.id, employers.name, employers.salary, e.id, e.name, e.salary
    6           , Alice         , 700
    4           , Bob           , 500
    2           , Tom           , 300
    

    然后限制

    limit(2)
    
    employers.id, employers.name, employers.salary, e.id, e.name, e.salary
    6           , Alice         , 700
    4           , Bob           , 500
    

    这就是我们需要的答案。


    我们为什么不

    1.

    Employer.order('salary desc').limit(2)
    

    因为这将使我们获得与名称无关的最高薪水记录

    employers.id, employers.name, employers.salary
    5           , Alice         , 600
    6           , Alice         , 700
    

    2.

    Employer.select('DISTINCT(name)').order('salary desc').limit(2)
    

    问题在于它只会保留名称的第一次出现然后排序

    employers.id, employers.name, employers.salary
    1           , Tom           , 200
    3           , Bob           , 400
    5           , Alice         , 600
    

    【讨论】:

      猜你喜欢
      • 2014-10-19
      • 2012-01-13
      • 2014-10-16
      • 2015-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多