【发布时间】:2017-05-03 18:47:14
【问题描述】:
我正在尝试从 PGExercises.com 解决这个特殊问题:
https://www.pgexercises.com/questions/aggregates/rankmembers.html
问题的要点是,我得到了一张俱乐部成员表和他们预订的 半小时 个时间段(获取列表是两个表的简单 INNER JOIN)。
我应该按预订的总小时数对成员进行降序排列,四舍五入到最近的 10。我还需要使用RANK() 窗口函数生成具有排名的列,并按排名对结果进行排序。 (结果产生 30 条记录。)
作者非常优雅的解决方案是这样的:
select firstname, surname, hours, rank() over (order by hours) from
(select firstname, surname,
((sum(bks.slots)+5)/20)*10 as hours
from cd.bookings bks
inner join cd.members mems
on bks.memid = mems.memid
group by mems.memid
) as subq
order by rank, surname, firstname;
不幸的是,作为一个 SQL 新手,我非常不雅的解决方案更加复杂,使用 CASE WHEN 并将数字转换为文本,以便查看最后一位数字以决定是否进行四舍五入 或向下:
SELECT
firstname,
surname,
CASE
WHEN (SUBSTRING(ROUND(SUM(slots*0.5),0)::text from '.{1}$') IN ('5','6','7','8','9','0')) THEN CEIL(SUM(slots*0.5) /10) * 10
ELSE FLOOR(SUM(slots*0.5) /10) * 10
END AS hours,
RANK() OVER(ORDER BY CASE
WHEN (SUBSTRING(ROUND(SUM(slots*0.5),0)::text from '.{1}$') IN ('5','6','7','8','9','0')) THEN CEIL(SUM(slots*0.5) /10) * 10
ELSE FLOOR(SUM(slots*0.5) /10) * 10
END DESC) as rank
FROM cd.bookings JOIN cd.members
ON cd.bookings.memid = cd.members.memid
GROUP BY firstname, surname
ORDER BY rank, surname, firstname;
尽管如此,我还是几乎做到了——在 30 条记录中,我得到了一个极端情况,其 firstname 是 'Ponder' 而 lastname 是 '斯蒂芬斯。他的四舍五入小时数是124.5,但解决方案坚持将其四舍五入到最接近的10应该产生120的结果,而我的解决方案产生130。
(顺便说一句,还有其他几个例子,比如我的和练习作者的解决方案中的204.5向上舍入到210。)
我的舍入逻辑有什么问题?
【问题讨论】:
标签: sql postgresql integer window-functions integer-division