MySQL PHP:优化排名查询和计数子查询教程
这是原始数据,并希望根据得分(count(tbl\_1.id))对它们进行排名.
[tbl_1]
===========
id | name
===========
1 | peter
2 | jane
1 | peter
2 | jane
3 | harry
3 | harry
3 | harry
3 | harry
4 | ron
因此,制作临时表(tbl\_2)来计算每个id的分数.
SELECT id, name, COUNT( id ) AS score
FROM tbl_1
GROUP BY id
ORDER BY score DESC;
LIMIT 0, 30;
然后结果是;
[tbl_2]
===================
id | name | score
===================
3 | harry | 4
1 | peter | 2
2 | jane | 2
4 | ron | 1
然后查询这个;
SELECT v1.id, v1.name, v1.score, COUNT( v2.score ) AS rank
FROM votes v1
JOIN votes v2 ON v1.score < v2.score
OR (
v1.score = v2.score
AND v1.id = v2.id
)
GROUP BY v1.id, v1.score
ORDER BY v1.rank ASC, v1.id ASC
LIMIT 0, 30;
然后结果是;
==========================
id | name | score | rank
==========================
3 | harry | 4 | 1
1 | peter | 2 | 2
2 | jane | 2 | 2
4 | ron | 1 | 4
是否可以很好地在一个事务(查询)中执行此操作?
解决方法:
是的,可以在单个查询中执行此操作.但它在MySQL中是一个完整的毛球,因为MySQL没有简单的ROWNUM操作,你需要一个用于排名计算.
这是您显示排名的投票查询. @ranka变量用于对行进行编号.
SELECT @ranka:=@ranka+1 AS rank, id, name, score
FROM
(
SELECT id,
name,
COUNT( id ) AS score
FROM tbl_1
GROUP BY id
ORDER BY score DESC, id
) votes,
(SELECT @ranka:=0) r
正如您已经发现的那样,您需要自行加入此项以获得正确的排名(正确处理关系).因此,如果您接受查询并将两个引用替换为您的投票表,每个引用都有自己的子查询版本,那么您将获得所需的内容.
SELECT v1.id,
v1.name,
v1.score,
COUNT( v2.score ) AS rank
FROM (
SELECT @ranka:=@ranka+1 AS rank,
id,
name,
score
FROM
(
SELECT id,
name,
COUNT( id ) AS score
FROM tbl_1
GROUP BY id
ORDER BY score DESC, name
) votes,
(SELECT @ranka:=0) r) v1
JOIN (
SELECT @rankb:=@rankb+1 AS rank,
id,
name,
score
FROM
(
SELECT id,
name,
COUNT( id ) AS score
FROM tbl_1
GROUP BY id
ORDER BY score DESC, name
) votes,
(SELECT @rankb:=0) r) v2
ON (v1.score < v2.score) OR
(v1.score = v2.score AND v1.id = v2.id)
GROUP BY v1.id, v1.score
ORDER BY v1.rank ASC, v1.id ASC
LIMIT 0, 30;
告诉你这是一个毛球.请注意,在您自行加入的子查询的两个版本中需要不同的@ranka和@rankb变量,以使行编号正常工作:这些变量在MySQL中具有连接范围,而不是子查询范围.
http://sqlfiddle.com/#!2/c5350/1/0显示了这个工作.
编辑:使用PostgreSQL的RANK()函数更容易做到这一点.
SELECT name, votes, rank() over (ORDER BY votes)
FROM (
SELECT name, count(id) votes
FROM tab
GROUP BY name
)x