我有Light Athletic比赛结果的表格。球员获得前三名的积分。 我需要列出他们的分数的田径名称。 我有这个:
SELECT NAME, SUM(many) as sum FROM
(
(SELECT NAME, count(*) * (SELECT points from "points for place" where place = 1) as many
FROM RESULTS R1 WHERE
(SELECT count(*) FROM RESULTS R2 WHERE
R1.result < R2.result
AND R1.DISCIPLINE = R2.DISCIPLINE
AND R1.CITY = R2.CITY) = 0
GROUP BY NAME)
UNION
(SELECT NAME, count(*) * (SELECT points from "points for place" where place = 2) as many
FROM RESULTS R1 WHERE
(SELECT count(*) FROM RESULTS R2 WHERE
R1.result < R2.result
AND R1.DISCIPLINE = R2.DISCIPLINE
AND R1.CITY = R2.CITY) = 1
GROUP BY NAME)
UNION
(SELECT NAME, count(*) * (SELECT points from "points for place" where place = 3) as many
FROM RESULTS R1 WHERE
(SELECT count(*) FROM RESULTS R2 WHERE
R1.result < R2.result
AND R1.DISCIPLINE = R2.DISCIPLINE
AND R1.CITY = R2.CITY) = 2
GROUP BY NAME)
)
GROUP BY NAME ORDER BY SUM;
我有三次几乎相同的冗余代码。如果这不是取决于地方,我可以使用View ...
答案 0 :(得分:3)
我认为你可以从根本上简化为:
SELECT name, sum(p.points) AS total_points
FROM (
SELECT r1.name
,sum((r1.result > r2.result)::int) + 1 AS place
FROM results r1
LEFT JOIN results r2 USING (discipline, city)
GROUP BY 1
HAVING sum((r1.result > r2.result)::int) < 3
) r
JOIN "points for place" p USING (place)
GROUP BY r.name
ORDER BY total_points;
使用 PostgreSQL 进行测试 由于OP后来宣布了Oracle,这里是 Oracle 的另一个版本:
SELECT name, SUM(p.points) AS total_points
FROM (
SELECT r1.name
,SUM(CASE WHEN r1.result > r2.result THEN 1 ELSE 0 END) + 1 AS place
FROM results r1
LEFT JOIN results r2 USING (discipline, city)
GROUP BY r1.name
HAVING SUM(CASE WHEN r1.result > r2.result THEN 1 ELSE 0 END) < 3
) r
JOIN "points for place" p USING (place)
GROUP BY r.name
ORDER BY total_points;
应该提供与问题中的查询相同的结果。只有更快更简单 ->sqlfiddle并排显示新查询和原始信息。
现在我知道这个查询是关于什么的:dense_rank()
显然是更好的解决方案。
对于Postgres,sum((r1.result < r2.result)::int)
计算r1.result
低于r2.result
的次数。 boolean
转换为integer
会产生1为TRUE,0为FALSE
对于Oracle,这个表达式也是如此:
SUM(CASE WHEN r1.result < r2.result THEN 1 ELSE 0 END)
我将1
添加到该计数中,并将其命名为place
,以便从表points
中获取"points for place"
。
答案 1 :(得分:2)
您可以通过以下方式简化:
select r.name,
sum(p.points) total_points
from (select city, discipline, name,
row_number() over (partition by city, discipline order by result) place
from results r) r
inner join "points for place" p
on p.place = r.place
where p.place <= 3
group by r.name
order by total_points desc;
*注意:如果可以存在平局,并且您希望两者都计为该位置,请使用dense_rank()
代替row_number()
考虑到您的测试数据,where p.place <= 3
也可能是多余的,因为您只有3个得分......所以您可以省略它。我已经离开了。
但令我感到困惑的是,在你原来的SQL和Erwins的答案中,你们两个都倒置了。那个跑得最久的家伙是第一名?!
,即你的小提琴:
-- RESULTS --
INSERT INTO results VALUES
('9.87', 'Doha', '100m', 'Justin GATLIN');
...
INSERT INTO results VALUES
('10.28', 'Doha', '100m', 'Jimmy VICAUT');
现在我在9.87秒内读到Justin WON。但你们都认为这是吉米的胜利。
如果是这样,那么分析应该是
partition by city, discipline order by result desc