在Postgres中将数字舍入到最接近的10

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表示数百,依此类推.


Boh*_*ian 7

要四舍五入到任何数字(范围)的最接近倍数:

round(<value> / <range>) * <range>
Run Code Online (Sandbox Code Playgroud)

“最近”意味着在范围边界之间正好中间的值被四舍五入。

这适用于任意范围,如果您想,您可以四舍五入到最近130.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)