name
如果我们可以使用 SQL 标准函数对每个PARTITIONed BY使用 ROW_NUMBER,这将相当容易company
。(ROW_NUMBER 给了我们一个“简单的排名”或简单的编号,没有平局也没有差距。)这基本上是@zebediah49 在他的评论中的提议。遗憾的是,MySQL 今天无法做到这一点。
@GordonLindoff 的答案使用自联接技术在 MySQL 中模拟了此功能。这是另一种方法。
首先,我们按公司对每个人进行分组,然后使用用户变量在全球范围内天真地对他们进行排名。所以,A公司的三个人变成了#1、#2和#3,B公司的两个人变成了#4和#5,以此类推:
company | name == ROW_NUMBER()d after ==> company | name | rank
--------+-------- == GROUP BY `company` ==> --------+---------+------
A | Alice A | Alice | 1
B | Bob A | Charlie | 2
A | Charlie A | Deborah | 3
A | Deborah B | Bob | 4
B | Erwin B | Erwin | 5
在 MySQL 中模拟 ROW_NUMBER的用户变量技术很容易搜索,但这里有一个来自另一个 SO 答案的紧凑演示。
现在,如果我们根据公司内的人数对全球幼稚排名进行 MOD,我们将得到“分区排名”,即公司内的相对排名:
company | name | rank | npeople | rank % npeople
--------+----------+------+---------+----------------
A | Alice | 1 | 3 | 1
A | Charlie | 2 | 3 | 2
A | Deborah | 3 | 3 | 0
B | Bob | 4 | 2 | 0
B | Erwin | 5 | 2 | 1
综上所述,加入查询以计算每家公司的人数,我们得到:
SELECT id, name, ranked.company
FROM ( SELECT tbl.id, tbl.name, tbl.company, (@rn := @rn + 1) AS rn
FROM tbl
JOIN (SELECT @rn := 0) vars
WHERE tbl.name LIKE '%John%'
ORDER BY company) ranked
JOIN (SELECT company, COUNT(id) AS npeople FROM tbl GROUP BY company) companies
ON ranked.company = companies.company
ORDER BY rn MOD companies.npeople, company