neu*_*ron 5 sql postgresql integer integer-division window-functions
我正在尝试从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;
Run Code Online (Sandbox Code Playgroud)
不幸的是,作为一个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;
Run Code Online (Sandbox Code Playgroud)
尽管如此,我还是差不多把它弄得恰到好处 - 在30条记录中,我得到了一个边缘案例,其名字是'Ponder'而且姓氏是'Stephens'.他的小时数是124.5,但解决方案坚持将其四舍五入到最近的10应该会产生结果120,同时我的解决方案产生130.
(顺便说一下,还有其他一些例子,如204.5舍入到210这两个矿山和锻炼作者的解决方案.)
我的舍入逻辑出了什么问题?
Gor*_*off 17
如果要舍入到最接近的10,则使用内置round()函数:
select round(<whatever>, -1)
Run Code Online (Sandbox Code Playgroud)
第二个参数可以是负数,-1表示数十,-2表示数百,依此类推.
要四舍五入到任何数字(范围)的最接近倍数:
round(<value> / <range>) * <range>
Run Code Online (Sandbox Code Playgroud)
“最近”意味着在范围边界之间正好中间的值被四舍五入。
这适用于任意范围,如果您想,您可以四舍五入到最近13或0.05也可以:
round(64 / 10) * 10 —- 60
round(65 / 10) * 10 —- 70
round(19.49 / 13) * 13 -- 13
round(19.5 / 13) * 13 -- 26
round(.49 / .05) * .05 -- 0.5
round(.47 / .05) * .05 -- 0.45
Run Code Online (Sandbox Code Playgroud)