我有一个“积分榜”查询,显示我所在的联赛的统计数据。我试图根据一些条件订购查询。
我能描述它的最好方法是它应该像两张桌子一样。排名(1-25)的队伍应该排在一起,排名(26-42)的队伍应该排在一起。
这是我的查询。
SELECT m.Team AS team
, SUM( r.points ) AS points
, SUM(CASE
WHEN rank = 1 THEN 1
ELSE 0
END) AS Wins
, SUM(CASE
WHEN rank < 6 THEN 1
ELSE 0
END) AS T5
, SUM(CASE
WHEN rank < 11 THEN 1
ELSE 0
END) AS T10
, SUM(CASE
WHEN rank < 21 THEN 1
ELSE 0
END) AS T20
, ROUND(Avg(r.points),2) AS ppr
, ROUND(Avg(r.rank),2) as avg_finish
, MIN(r.rank) as best
FROM members m
LEFT JOIN results r ON r.team_id = m.M_ID
GROUP BY team
ORDER BY
CASE
WHEN COUNT(*) < 26
THEN Wins
WHEN COUNT(*) > 25
THEN points
END DESC, points DESC;
由于我的别名“Wins”,我收到错误“引用'Wins'不支持(引用群组功能)。相反,我尝试过:
ORDER BY
CASE
WHEN COUNT(*) < 26
THEN SUM(CASE
WHEN rank = 1 THEN 1
ELSE 0
END)
WHEN COUNT(*) > 25
THEN points
END DESC, points DESC;
这成功订购了我的桌子,但没有考虑COUNT(*)&gt; 25 CASE条款,只是按顺序,然后点。关于如何重构ORDER BY子句的任何想法?
答案 0 :(得分:1)
您应该在外部查询中执行ORDER BY
,因为Wins
子句中无法访问列别名ORDER
。
SELECT * FROM (
SELECT m.Team AS team
, SUM( r.points ) AS points
, SUM(CASE
WHEN rank = 1 THEN 1
ELSE 0
END) AS Wins
, SUM(CASE
WHEN rank < 6 THEN 1
ELSE 0
END) AS T5
, SUM(CASE
WHEN rank < 11 THEN 1
ELSE 0
END) AS T10
, SUM(CASE
WHEN rank < 21 THEN 1
ELSE 0
END) AS T20
, ROUND(Avg(r.points),2) AS ppr
, ROUND(Avg(r.rank),2) as avg_finish
, MIN(r.rank) as best
FROM members m
LEFT JOIN results r ON r.team_id = m.M_ID
GROUP BY team ) XXX
ORDER BY
CASE
WHEN COUNT(*) < 26
THEN Wins
WHEN COUNT(*) > 25
THEN points
END DESC, points DESC;
答案 1 :(得分:0)
对Wins
的引用应该有效。 MySQL接受order by
中的列别名,因此不需要子查询。
但是,您可能希望逻辑为:
ORDER BY (CASE WHEN COUNT(*) < 26 THEN 1 ELSE 2 END), -- put the top ranking first,
(CASE WHEN COUNT(*) < 26 THEN wins END) DESC,
points DESC
在MySQL中,您还可以简化select
逻辑:
SELECT m.Team AS team, SUM( r.points ) AS points,
SUM(rank = 1) then Wins,
SUM(rank < 6) as T5,
SUM(rank < 11) as T10,
SUM(rank < 21) as T20
. . .
编辑:
我认为您想要的ORDER BY
是:
ORDER BY (points <= 26) DESC, -- put the top ranking first,
wins desc,
points DESC
答案 2 :(得分:0)
不幸的是,MySQL不支持ROW_NUMBER()
或RANK()
等分析函数。如果确实如此,我们可以使用ROW_NUMBER()
函数根据特定订单识别“前25行”。但是有两种方法可以模拟ROW_NUMBER()
函数。
一种方法是使用带有用户定义变量的技巧来模拟它。我们使用这种方法是我们需要标记行,并返回值。
在这种情况下,我们只关心一支球队是否“进入前25名”。所以我们可以运行一个单独的查询来返回“前25名”团队。
例如,此查询获取两个集......“所有团队”(a
)的集合结果以及“前25名”团队的集合({{ 1}}),并匹配使用外连接操作的那些:
t
内联视图“a”是获取所有团队的查询。
内联视图“t”本质上是相同的查询,但有一个ORDER BY和LIMIT子句,因此它最多返回25行。 ORDER BY在LIMIT之前应用,因此它将返回具有最高分数的25支球队。 (其他表达式包含在ORDER BY中,以使结果更具确定性......如果列表中第25和第26的两个团队具有相同的点数......
外部查询识别来自 SELECT a.*
FROM (
SELECT m.team AS team
, SUM( r.points ) AS points
, SUM(IF( r.rank=1 ,1,0)) AS wins
, SUM(IF( r.rank<6 ,1,0)) AS t5
, SUM(IF( r.rank<11 ,1,0)) AS t10
, SUM(IF( r.rank<21 ,1,0)) AS t20
, ROUND(AVG( r.points ),2) AS ppr
, ROUND(AVG( r.rank ),2) AS avg_finish
, MIN( r.rank ) AS best
FROM members m
LEFT
JOIN results r
ON r.team_id = m.m_id
GROUP BY m.team
) a
LEFT
JOIN ( SELECT tm.team AS team
, SUM(IF( tr.rank=1 ,1,0)) AS wins
FROM members tm
LEFT
JOIN results tr
ON tr.team_id = tm.m_id
GROUP BY tm.team
ORDER
BY SUM( tr.points ) DESC
, SUM(IF( tr.rank=1 ,1,0)) DESC
, tr.team_id DESC
LIMIT 25
) t
ON t.team = ta.team
ORDER
BY t.wins DESC
, a.points DESC
, a.team DESC
的哪个团队位于“前25名”中,并应用适当的排序。 (请注意,没有来自a
的匹配行的团队将为t
中的所有列提供NULL值...即t
将为NULL,因此ORDER BY可以正常工作。
我们不一定需要从内嵌视图t.wins
返回wins
。我们可以通过测试NULL值来检查是否从t
返回了匹配的行。例如
t
答案 3 :(得分:0)
您的问题是,在按points
对结果进行排序之前,您不知道排名。如果你知道等级,你可以用
ORDER BY (rank > 25) ASC
, CASE WHEN rank <= 25 THEN Wins ELSE 0 END
, points
确定MySQL排名的一种方法是将排序结果存储在具有AUTO_INCREMENT排名列的临时表中。
DROP TEMPORARY TABLE IF EXISTS tmp_teams;
CREATE TEMPORARY TABLE tmp_teams (
rank INT AUTO_INCREMENT PRIMARY KEY,
team varchar(255),
points INT,
Wins INT,
T5 INT,
T10 INT,
T20 INT,
ppr INT,
avg_finish INT,
best INT
) AS
SELECT null AS rank
, m.Team AS team
, SUM( r.points ) AS points
, SUM(CASE
WHEN rank = 1 THEN 1
ELSE 0
END) AS Wins
, SUM(CASE
WHEN rank < 6 THEN 1
ELSE 0
END) AS T5
, SUM(CASE
WHEN rank < 11 THEN 1
ELSE 0
END) AS T10
, SUM(CASE
WHEN rank < 21 THEN 1
ELSE 0
END) AS T20
, ROUND(Avg(r.points),2) AS ppr
, ROUND(Avg(r.rank),2) as avg_finish
, MIN(r.rank) as best
FROM members m
LEFT JOIN results r ON r.team_id = m.M_ID
GROUP BY team
ORDER BY points DESC, Wins DESC, r.team_id ASC -- define the order for rank
;
SELECT *
FROM tmp_teams
ORDER BY (rank > 25) ASC
, CASE WHEN rank <= 25 THEN Wins ELSE 0 END
, points;
另一种方法是使用会话变量(@rank),它将在有序子查询中递增:
SELECT *
FROM (
SELECT m.Team AS team
, SUM( r.points ) AS points
, SUM(CASE
WHEN rank = 1 THEN 1
ELSE 0
END) AS Wins
, SUM(CASE
WHEN rank < 6 THEN 1
ELSE 0
END) AS T5
, SUM(CASE
WHEN rank < 11 THEN 1
ELSE 0
END) AS T10
, SUM(CASE
WHEN rank < 21 THEN 1
ELSE 0
END) AS T20
, ROUND(Avg(r.points),2) AS ppr
, ROUND(Avg(r.rank),2) as avg_finish
, MIN(r.rank) as best
, @rank := @rank + 1 AS rank
FROM members m
LEFT JOIN results r ON r.team_id = m.M_ID
CROSS JOIN (select @rank := 0) AS init_rank
GROUP BY team
ORDER BY points DESC, Wins DESC, r.team_id ASC -- define the order for rank
LIMIT 1000000000 -- workaround for some versions/settings to force sorting a subquery result
) sub
ORDER BY (rank > 25) ASC
, CASE WHEN rank <= 25 THEN Wins ELSE 0 END
, points
答案 4 :(得分:0)
它终于奏效了。保罗,你的排名是正确的。以下是Mahmoud提供我使用的排名的链接: Rank Values
SET @rownum = 0;
SELECT *, (@rownum := @rownum + 1) AS chase FROM (
SELECT m.Team AS team
, SUM( r.points ) AS points
, SUM(r.rank = 1) AS Wins
, SUM(r.rank < 6) AS T5
, SUM(r.rank < 11) AS T10
, SUM(r.rank < 21) AS T20
, ROUND(Avg(r.points),2) AS ppr
, ROUND(Avg(r.rank),2) as avg_finish
, MIN(r.rank) as best
FROM members m
LEFT JOIN results r ON r.team_id = m.M_ID
GROUP BY team
ORDER BY points DESC ) AS ptotal
ORDER BY CASE
WHEN chase <= 24
THEN Wins
END DESC, points DESC;
谢谢大家的帮助。我刚刚开始使用这个网站,无法相信你们都有多大帮助。当我在路上遇到问题时,我知道在哪里看看!