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

Rounding numbers to the nearest 10 in Postgres

我正在尝试解决来自 PGExercises.com 的这个特定问题:

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

问题的要点是,我得到了 table 个俱乐部成员和他们预订的 半小时 个时间段(获取列表是一个两个 tables).

的简单 INNER JOIN

我应该按总预订时数 对会员进行降序排列,四舍五入到最接近的 10。我还需要使用 RANK() window 函数生成一个带有排名的列,然后按排名对结果进行排序。 (结果产生 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' 和 是'Stephens'。他的四舍五入小时数是 124.5,但解决方案坚持将其四舍五入到最接近的 10 应该产生 120 的结果,而我的解决方案产生 130.

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

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

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

select round(<whatever>, -1)

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

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

round(<value> / <range>) * <range>

“最接近的”表示恰好范围边界之间一半的值被四舍五入。

这适用于任意范围,如果您愿意,您也可以四舍五入到最接近的 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

我一直在努力解决类似的问题。我需要将数字四舍五入到最接近的 50 的倍数。Gordon 在这里的建议不起作用。

我的第一次尝试是 SELECT round(120 / 50) * 50,结果是 100。然而,SELECT round(130 / 50) * 50给了100。这是错误的;最接近的倍数是 150.

诀窍是使用浮点数进行除法,例如SELECT round(130 / 50.0) * 50 将给予 150.

原来做 x/y,其中 xy 是整数,等同于 trunc(x/y)。其中浮动除法正确舍入到最接近的倍数。

我认为 Bohemian 的公式不正确。

通用公式为:

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

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