SQL 不带小数的四舍五入整数
SQL Rounding integers with no decimals
我遇到了一个看似简单的问题。我只想显示没有小数位的百分比,并将总数加到 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 中减去可能行不通......
对于您的特定问题,我得到的数字加起来为 100:
select isMale, count(*), sum(count(*)) over (),
round(100.0 * count(*) / sum(count(*)) over (), 0)
from genderTable t
group by isMale;
您的实施的实际问题是 SQL 服务器执行整数运算。因此,表达式 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 中减去它。
编辑:
"integer" 个版本:
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 的问题。
刚刚看到上面的回答。干得好戈登!
这是一个相似版本的答案:
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
我遇到了一个看似简单的问题。我只想显示没有小数位的百分比,并将总数加到 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 中减去可能行不通......
对于您的特定问题,我得到的数字加起来为 100:
select isMale, count(*), sum(count(*)) over (),
round(100.0 * count(*) / sum(count(*)) over (), 0)
from genderTable t
group by isMale;
您的实施的实际问题是 SQL 服务器执行整数运算。因此,表达式 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 中减去它。
编辑:
"integer" 个版本:
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 的问题。
刚刚看到上面的回答。干得好戈登!
这是一个相似版本的答案:
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