SQL舍入整数,没有小数

时间:2015-04-16 19:20:29

标签: sql sql-server tsql rounding

我有一个看似简单的问题。我只想显示没有小数位的百分比,并将总数加到100.这里有一点点片段:

create table genderTable
(person varchar(10),
isMale varchar(5))

insert into genderTable values ('Mary', 'false')
insert into genderTable values ('Frank', 'true')
insert into genderTable values ('Bill', 'true')
insert into genderTable values ('Jessie', 'false')
insert into genderTable values ('Sue', 'false')
insert into genderTable values ('Beth', 'false')
insert into genderTable values ('Kris', 'false')

declare @total as int
set @total = 7
select
CASE isMale
   WHEN 'True' THEN 'Male'
   ELSE 'Female'
END as Gender,
CASE 
WHEN @total > 0 THEN ROUND((count(isMale) * 100 / @total), 0)
ELSE 0
END as GenderPercent
from genderTable
group by  isMale

总计增加到99%而不是100%。我尝试了各种舍入,但我得到一个小数或99%。有帮助吗?请记住,在另一个例子中,我必须对有两个以上值的种族做同样的事情,所以从100减去可能不会工作......

2 个答案:

答案 0 :(得分:2)

对于你的特殊问题,当我这样做时,我得到的数字加起来为100:

select isMale, count(*), sum(count(*)) over (),
       round(100.0 * count(*) / sum(count(*)) over (), 0)
from genderTable t
group by isMale;

您的实现的实际问题是SQL Server执行整数运算。因此,表达式ROUND((count(isMale) * 100 / @total), 0)正在使用整数除法进行计算 - 在实现floor()之前获取比率的round()

有办法做你想做的事。它们在SQL Server 2012+中比在早期版本中更容易实现:

select isMale,
       round(100.0 * cnt / tot, 0) as p,
       (case when seqnum = 1
             then 100 - sum(round(100.0 * cnt / tot, 0)) over (order by seqnum desc rows between unbounded preceding and 1 preceding)
             else round(100.0 * cnt / tot, 0) 
        end) as p_tot_100
from (select isMale, count(*)*1.0 as cnt, sum(1.0*count(*)) over () as tot,
             row_number() over (order by isMale) as seqnum
      from genderTable t
      group by isMale
     ) t;

我们的想法是对所有其他行的舍入版本求和,并从其中一行中减去100。

编辑:

这些的“整数”版本:

select isMale, count(*), sum(count(*)) over (),
       cast(round(100.0 * count(*) / sum(count(*)) over (), 0) as int)
from genderTable t
group by isMale;

select isMale,
       round(100.0 * cnt / tot, 0) as p,
       cast((case when seqnum = 1
                  then 100 - sum(round(100.0 * cnt / tot, 0)) over (order by seqnum desc rows between unbounded preceding and 1 preceding)
                  else round(100.0 * cnt / tot, 0) 
             end) as int) as p_tot_100
from (select isMale, count(*)*1.0 as cnt, sum(1.0*count(*)) over () as tot,
             row_number() over (order by isMale) as seqnum
      from genderTable t
      group by isMale
     ) t;

我很确定小整数是否完全表示,即使使用浮点表示,因此round()产生的值不会出现问题,例如29.99999999999997而不是30。

答案 1 :(得分:0)

我刚看到上面的答案。好工作戈登!

以下是答案的类似版本:

SELECT CASE isMale
    WHEN 'True'
        THEN 'Male'
    ELSE 'Female'
    END AS Gender
   ,CAST(left(round(count(isMale) * 100.00 /(select count(*) from gendertable), 0),2) AS VARCHAR) + '%' AS GenderPercent
FROM genderTable
GROUP BY isMale