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

时间:2016-12-18 16:21:14

标签: sql postgresql integer window-functions integer-division

我试图从PGExercises.com解决这个特殊问题:

https://www.pgexercises.com/questions/aggregates/rankmembers.html

问题的要点是我给了一张俱乐部成员表和他们预订的半小时时段(获取列表是两个表的简单内部联接)

我应该按总小时预订产生降序排名,并四舍五入到最近的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并将数字转换为文本以查看最后一个数字以决定是否围绕向上 down

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条记录中,我得到了一个边缘案例,其名字是'思考'和姓氏是' Stephens'。他的小时数为124.5,但解决方案坚持将其四舍五入到最接近的10会产生120的结果,而我的解决方案产生130

(顺便说一句,还有其他一些例子,例如204.5在我和演习作者的解决方案中四舍五入到210。)

我的舍入逻辑有什么问题?

4 个答案:

答案 0 :(得分:10)

如果要舍入到最接近的10,请使用内置的round()函数:

select round(<whatever>, -1)

第二个参数可以是负数,-1表示数十,-2表示数百,依此类推。

答案 1 :(得分:2)

要舍入到10最近倍数:

round(<value> / 10 - .5) * 10

将以向上舍入以5-9结尾的值,否则将向下。

这个通用公式为:

round(<value> / <range> - .5) * <range>

如果你愿意,你可以四舍五入到最近的13

答案 2 :(得分:0)

我一直在努力解决同等问题。我需要将数字舍入到最接近的50的倍数。戈登的建议在这里不起作用。

我的第一次尝试是SELECT round(120 / 50) * 50,它提供了100。但是,SELECT round(130 / 50) * 50给了100。这是错的;最近的倍数是150

诀窍是使用浮点数划分,例如SELECT round(130 / 50.0) * 50将提供150

事实证明,x/yx为整数,y等同于trunc(x/y)。浮点除法正确舍入到最接近的倍数。

答案 3 :(得分:0)

我认为波希米亚的公式不正确。

通用公式为:

round((value +(range / 2))/ range)*范围

因此要转换为最接近的50,取整((103 + 25)/ 50)* 50->将得到100