我正试图从www.example.com解决这个特殊的问题PGExercises.com:
https://www.pgexercises.com/questions/aggregates/rankmembers.html
这个问题的要点是,我得到了一张俱乐部成员的table和他们预订的 * 半小时 * 时间段(获取列表是两张table的简单内部连接)。
我应该按照 total hours booked(四舍五入到 * 最接近的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 是'Stephens'。他的四舍五入的小时数是124.5
,但解决方案坚持将其四舍五入到最接近的10应该产生120
的结果,而我的解决方案产生130
。
(By顺便说一句,还有其他几个例子,比如204.5
向上舍入到210
,这在我的解决方案和练习作者的解决方案中都有。)
我的四舍五入逻辑有什么问题?
5条答案
按热度按时间rhfm7lfc1#
如果要四舍五入到最接近的10,请使用内置的
round()
函数:第二个参数可以为负,-1表示十位,-2表示百位,依此类推。
d8tt03nd2#
四舍五入到任何数字(范围)的 * 最接近 * 倍数:
“最接近”表示范围边界之间正好一半的值被向上舍入。
这适用于任意范围,如果您想要,也可以舍入到最接近的
13
或0.05
:6ie5vjzr3#
我也遇到过类似的问题,我需要把数字四舍五入到50的整数倍,戈登的建议在这里行不通。
我的第一次尝试是
SELECT round(120 / 50) * 50
,它给出了100
,但是SELECT round(130 / 50) * 50
给出了100
,这是错误的;最接近的倍数是150
。诀窍是使用浮点数除法,例如
SELECT round(130 / 50.0) * 50
将给予150
。结果是
x/y
,其中x
和y
是整数,等价于trunc(x/y)
,其中浮点除法正确地舍入到最近的倍数。qxsslcnc4#
我不认为波希米亚的公式是正确的。
一般公式为:
舍入((值+(范围/2))/范围)* 范围
因此,若要转换为最接近50,四舍五入((103 + 25)/50)* 50 --〉将给予100
zmeyuzjn5#
一个修改版本的作者的优雅的解决方案,工程:
我希望你觉得有用