MySQL: правильное округление процентов

#mysql #rounding #percentage

#mysql #округление #процент

Вопрос:

У меня есть таблица t(int, float, float, float) в базе данных MySQL со следующими значениями:

ID v1 v2 v3
1 0.25 0.75 0
2 0.125 0 0.875

Гарантируется, что v1 v2 v3 ==1 для каждой строки.

Примечание: v1, v2 и v3 являются числами с плавающей запятой, поэтому в некоторых случаях v1 v2 v3 может быть 1 /- 1E-38

Мне нужно сгенерировать целочисленные проценты на выходе (т. Е. Целые числа от 0 до 100), которые бы добавляли до 100 для каждой записи и в то же время представляли исходные значения как можно точнее.

Для приведенной выше выборки данных ожидаемый результат будет либо:

ID p1 p2 p3
1 25 75 0
2 13 0 87

Или:

ID p1 p2 p3
1 25 75 0
2 12 0 88

(оба вышеуказанных вывода приемлемы)

Мое текущее решение:

Шаг 1: вычисление p1tmp = round(100*v1), p2tmp = round(100*v2), p3tmp = round(100*v3)

Шаг 2: вычисление:

 p1 = CASE
    WHEN p1tmp = GREATEST(p1tmp, p2tmp, p3tmp) AND GREATEST(p1tmp, p2tmp, p3tmp) > LEAST(p1tmp, p2tmp, p3tmp)
    THEN 100 - p2tmp - p3tmp ELSE p1tmp END AS p1,
p2 = CASE
    WHEN p2tmp = GREATEST(p1tmp, p2tmp, p3tmp) AND GREATEST(p1tmp, p2tmp, p3tmp) > LEAST(p1tmp, p2tmp, p3tmp)
    THEN 100 - p1tmp - p3tmp ELSE p2tmp END AS p2,
p3 = CASE
    WHEN p3tmp = GREATEST(p1tmp, p2tmp, p3tmp) AND GREATEST(p1tmp, p2tmp, p3tmp) > LEAST(p1tmp, p2tmp, p3tmp)
    THEN 100 - p1tmp - p2tmp ELSE p3tmp END AS p3
 

Несмотря на математическую корректность, приведенное выше решение не очень элегантно. Код запутанный, нечитаемый и его нелегко расширить до случая с 4 или 5 значениями (мое текущее требование — 4 значения, т.Е. v1, v2, v3, v4, но оно может измениться в будущем).

Я попытался применить метод округления до ближайшего четного, но он работал только для пары переменных (т.Е. v1, v2, а не v1, v2, v3).

Любые идеи приветствуются.

Комментарии:

1. Разве не гарантируется, что один v будет равен нулю?

2. Нет. Любое количество Vs может быть ненулевым для любой отдельной записи.

Ответ №1:

Решение MSSQL, но может быть легко принято. — сделайте сводку

 declare @id int
set @id =4 -- take a single row data

create table #row(x float, procent int, col int);
insert into #row
 select v1,0,1  from t where id = @id union all
 select v2,0,2  from t where id = @id union all 
 select v3,0,3  from t where id = @id;


with cte as 
(select x, 
case when x != (select max(x) from #row) then ROUND(x*100,0) else ROUND(x*100,0,1) end x2
from #row )

select * from cte -- unpivoto

drop table #row