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

mqkwyuun  于 2022-12-18  发布在  PostgreSQL
关注(0)|答案(5)|浏览(173)

我正试图从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,这在我的解决方案和练习作者的解决方案中都有。)
我的四舍五入逻辑有什么问题?

rhfm7lfc

rhfm7lfc1#

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

select round(<whatever>, -1)

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

d8tt03nd

d8tt03nd2#

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

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
6ie5vjzr

6ie5vjzr3#

我也遇到过类似的问题,我需要把数字四舍五入到50的整数倍,戈登的建议在这里行不通。
我的第一次尝试是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),其中浮点除法正确地舍入到最近的倍数。

qxsslcnc

qxsslcnc4#

我不认为波希米亚的公式是正确的。
一般公式为:
舍入((值+(范围/2))/范围)* 范围
因此,若要转换为最接近50,四舍五入((103 + 25)/50)* 50 --〉将给予100

zmeyuzjn

zmeyuzjn5#

一个修改版本的作者的优雅的解决方案,工程:
我希望你觉得有用

select firstname, surname, round(hrs, -1) as hours, rank() over(order by 
round(hrs, -1) desc) as rank
from (select firstname, surname, sum(bks.slots) * 0.5 as hrs
from cd.members mems
inner join cd.bookings bks
on mems.memid = bks.memid
group by mems.memid) as subq
order by rank, surname, firstname;

相关问题