问题描述
我在 MysqL 数据库中有一个表 t(int,float,float)
,其值如下:
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 |
(以上两个输出都是可以接受的)
我目前的解决方案:
第一步:计算p1tmp = round(100*v1),p2tmp = round(100*v2),p3tmp = round(100*v3)
第 2 步:计算:
p1 = CASE
WHEN p1tmp = GREATEST(p1tmp,p2tmp,p3tmp) AND GREATEST(p1tmp,p3tmp) > LEAST(p1tmp,p3tmp)
THEN 100 - p2tmp - p3tmp ELSE p1tmp END AS p1,p2 = CASE
WHEN p2tmp = GREATEST(p1tmp,p3tmp)
THEN 100 - p1tmp - p3tmp ELSE p2tmp END AS p2,p3 = CASE
WHEN p3tmp = GREATEST(p1tmp,p3tmp)
THEN 100 - p1tmp - p2tmp ELSE p3tmp END AS p3
虽然在数学上是正确的,但上述解决方案并不是很优雅。代码复杂、不可读且不易扩展到具有 4 个或 5 个值的情况(我目前的要求实际上是 4 个值,即 v1、v2、v3、v4,但将来可能会改变)。
我尝试应用舍入到最接近偶数的方法,但它只适用于一对变量(即 v1、v2,而不是 v1、v2、v3)。
欢迎提出任何想法。
解决方法
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,1 from t where id = @id union all
select v2,2 from t where id = @id union all
select v3,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,1) end x2
from #row )
select * from cte -- unpivoto
drop table #row