mysql - 需要两个限制?

时间:2012-01-27 02:45:12

标签: mysql

如果一个表格包含由多个地理区域组成的组织成员多年来获得的奖励,那么mysql查询将显示每个区域的最高奖励者?通过此查询,我可以轻松获得所有地区的十大奖项获得者:

SELECT Membername,  count(Award)as Number FROM awards 
GROUP BY Membername
ORDER BY Number desc 
LIMIT 10

但是我需要一个每个区最高收入者的名单(其中大约有90个),我还没有把它弄好。

我试过了:

SELECT Membername,  District, count(Award)as Number FROM awards 
GROUP BY Membername, District
ORDER BY Number desc, District 
LIMIT 90

它对会员有准确的计数,但每个地区没有显示一个,所以一些地区出现不止一次。我如何让它列出每个地区的最高收入者,每个地区只出现一次?

3 个答案:

答案 0 :(得分:2)

您必须通过对每个区域应用“排名”来执行此操作,然后仅按每个级别获取= 1 ...如果区域基于ID,则加入位置的@LastDistrict默认为零。如果district是基于char的,则可以将其更改为=“”而不是匹配数据类型。

澄清发生了什么。 “AwardCounts”预查询按区域和成员执行整个查询,但奖励数量很多。然后,按地区和会员奖励计数(降序)排序,从而将最高奖励计数放在每个区的第一个位置。

它加入了另一个伪造的别名“SQLVars”,它只为查询创建了一个名为@RankSeq和@LastDistrict的内联变量。因此,第一次进入时,“DistRankSeq”将成为第一个区域的1,然后使用该区域的值填充“@LastDistrict”。同一地区的下一个条目(因为它将以正确的顺序排列)将被分配等级2,然后是3等等......当“最后”区域到新记录的任何变化时经过测试,等级被设置回1并重新开始。所以你可以有一个有100个成员的区,另一个有5个,另一个有17个......

所以,你的最终查询都有各自的等级......现在,申请最后的地区等级= 1 ...这样做,你也可以调整必须得到每个区的前3名成员(例如)......

select
      AwardCounts.District,
      AwardCounts.MemberName,
      AwardCounts.memberAwards,
      @RankSeq := if( @LastDistrict = AwardCounts.District, @RankSeq +1, 1 ) DistRankSeq,
      @LastDistrict := AwardCounts.District as ignoreIt
   from
      ( select 
              a.district,
              a.membername,
              count(*) as memberAwards
           from
              Awards a
           group by
              a.district,
              a.membername
           order by
              a.district,
              memberAwards desc ) AwardCounts

      JOIN (select @RankSeq := 0, @LastDistrict = 0 ) SQLVars
   HAVING
      DistRankSeq = 1

编辑每次反馈 如果它的聚合花费时间,那么我会做以下。创建一个新表,除了每个区的聚合,名称和区的初始排名。随着任何新记录被添加到此表中,触发器然后将一个添加到聚合表计数,然后检查该人在其区域内的位置并重新更新其新的排名位置。你可以更进一步,每个区表有一个只有“TOP”成员的表,每个区有一个人的名字。当一个新人到达顶部位置时,他们的名字会被放入表格中,覆盖最后一个人。

答案 1 :(得分:0)

使用 self-joins 有一种相当常见的方法可以做到这一点。诀窍是用搜索“那些没有更大的物品”来替换“最大”的搜索。正如你已经发现的那样

SELECT Membername,  District, count(Award) as Number FROM awards
GROUP BY Membername, District

为您提供奖励计数的良好结果。让我们写...来节省一些空间作为速记。

现在考虑

SELECT a.Membername, a.District, a.Number FROM (...) a LEFT JOIN (...) b
ON a.District=b.District
AND a.Number<b.Number
WHERE b.Membername IS NULL

...就是上面写的东西。它基本上是说,对于奖项中的每个条目(a),找到我在同一区域的所有条目(b)有更多奖项,并且只有在没有(b)的情况下才返回(a)。换句话说,a是冠军。

如果同一区内有多个成员具有相同的获胜计数,您将需要对此进行一些细化...此查询将返回所有绑定成员。你必须决定如何处理它。并注意那些根本没有任何奖项的地区......它们甚至不会出现在你的桌子上。

答案 2 :(得分:0)

There's a page specifically dedicated问题 - 如果您查看较旧的手册,您会看到max-concat trick - 这通常效率更高。