【问题标题】:SQL Rounding integers with no decimalsSQL 舍入不带小数的整数
【发布时间】:2015-04-16 19:20:29
【问题描述】:

我有一个看似简单的问题。我只想显示没有小数位的百分比,并且总加起来为 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.5、2.5。您永远不会得到加起来为 5 的整数。四舍五入时会发生这种情况。
  • 加起来然后四舍五入,也许吧?

标签: sql sql-server tsql rounding


【解决方案1】:

对于你的特殊问题,当我这样做时,我得到的数字加起来是 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) 正在使用整数除法进行计算——在实现round() 之前取比率的floor()

有很多方法可以做你想做的事。它们在 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 之类的值不会有问题。

【讨论】:

  • 我错过了什么吗?在第一个示例中,我仍然得到很多 .0000。第二个给了我一个错误(我使用的是2008)。假 5 7 71.000000000000 真 2 7 29.000000000000
  • @Laurel。 . .零不会影响任何东西,但可以将值转换回整数。
【解决方案2】:

我刚刚看到上面的答案。干得好,戈登!

这是答案的类似版本:

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

【讨论】:

  • 这个也是 .000 的女性 71.0000000000000% 男性 29.0000000000000% 我将使用 SSRS,所以也许它可以删除小数点?
  • 我相信在 SSRS 中您可以删除小数点。您只需要将列转换回 int。
  • 我确实更新了我的初始回复,所以希望这对你有用。
  • Bingo - 我认为这对我有用!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
  • 2022-11-24
  • 2022-12-03
  • 2021-08-08
相关资源
最近更新 更多