私はPGExercises.comからこの特定の問題を解決しようとしています:
https://www.pgexercises.com/questions/aggregates/rankmembers.html
質問の要点は、クラブメンバーの表と、彼らが予約した30分の時間枠が与えられていることです(リストを取得するのは簡単です) 2つのテーブルの内部結合)。
私は、予約された合計時間でメンバーの降順のランキングを作成し、最も近い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
を使用し、最後の桁を見て丸めるかどうかを決定するために数値をテキストに変換します upまたは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のレコードのうち、firstnameが 'Ponder'およびlastnameは「Stephens」です。彼の丸められた時間数は124.5
ですが、ソリューションでは、10に最も近い値に丸めると、120
の結果が生成され、私のソリューションでは130
が生成されると主張しています。
(ちなみに、私のものと演習の作成者のソリューションの両方で、204.5
を210
に切り上げるなど、他にもいくつかの例があります。)
丸めロジックの何が問題になっていますか?
10に最も近い値に丸める場合は、組み込みのround()
関数を使用します。
select round(<whatever>, -1)
2番目の引数は負の値にすることができ、-1は数十、-2は数百というようになります。
最も近い10
の倍数に丸めるには:
round(<value> / 10 - .5) * 10
これは、5〜9で終わる値の場合はpを丸め、それ以外の場合は切り捨てます。
これには、次の一般式があります。
round(<value> / <range> - .5) * <range>
したがって、必要に応じて、最も近い13
に丸めることができます。
私は同等の問題に苦しんでいます。数値を50の最も近い倍数に丸める必要がありました。ここでのゴードンの提案は機能しません。
私の最初の試みはSELECT round(120 / 50) * 50
で、これは_100
_を与えます。ただし、SELECT round(130 / 50) * 50
は_100
_を与えました。これは間違っています;最も近い倍数は_150
_です。
秘訣は、フロートを使用して分割することです。 SELECT round(130 / 50.0) * 50
は_150
_を提供します。
x
とy
が整数である_x/y
_を実行することは、trunc(x/y)
と同等であることがわかります。一方、浮動小数点除算は最も近い倍数に正しく丸められます。