这个问题实际上非常棘手!
这似乎很容易,但事实并非如此。
查询:
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)(这个薪水高于其他所有
这个名字的薪水)
或
第一种方法需要我们获取我不太喜欢的那个名字的所有记录。
第二个需要一种聪明的方式来说明没有比这个更高的记录。
返回 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