如何使用 SQL 语句计算百分比

Posted

技术标签:

【中文标题】如何使用 SQL 语句计算百分比【英文标题】:How to calculate percentage with a SQL statement 【发布时间】:2010-10-20 17:06:01 【问题描述】:

我有一个包含用户及其成绩的 SQL Server 表。为简单起见,假设有 2 列 - namegrade。因此,典型的行将是名称:“John Doe”,等级:“A”。

我正在寻找一个 SQL 语句,它可以找到所有可能答案的百分比。 (A、B、C 等......)另外,有没有办法在不定义所有可能答案的情况下做到这一点(打开文本字段 - 用户可以输入“通过/失败”、“无”等......)

我正在寻找的最终输出是 A: 5%, B: 15%, C: 40%, 等等...

【问题讨论】:

【参考方案1】:

    最高效的(使用over())。

    select Grade, count(*) * 100.0 / sum(count(*)) over()
    from MyTable
    group by Grade
    

    通用(任何 SQL 版本)。

    select Grade, count(*) * 100.0 / (select count(*) from MyTable)
    from MyTable
    group by Grade;
    

    使用 CTE,效率最低。

    with t(Grade, GradeCount) 
    as 
    ( 
        select Grade, count(*) 
        from MyTable
        group by Grade
    )
    select Grade, GradeCount * 100.0/(select sum(GradeCount) from t)
    from t;
    

【讨论】:

over() 在我的 SQL Server 2008 上完美运行,我做了数学确认。为了将其四舍五入到小数点后 2 位,我使用了 CAST(count() * 100.0 / sum(count()) over() AS DECIMAL(18, 2))。感谢您的帖子! 如果您在 100 乘法上溢出(例如 将表达式转换为数据类型 int 的算术溢出错误),请将其替换为分母中的除法:cast((count(*) / (sum(count(*)) over() / 100)) AS DECIMAL(18, 2)) as Percentage @RJB 为什么在将输出转换为小数时必须乘以 100.0 而不仅仅是 100? @AS91,因为转换为小数发生在除法操作之后。如果你留下一个 int (100),除以另一个 int 也会得到一个 int,这将对结果进行四舍五入。这就是为什么诀窍总是在实际除法之前强制对被除数进行强制转换(您可以乘以像 1.0 这样的文字小数或强制转换/转换) 选项 1 和 over() 在 Postgresql 10 上效果很好【参考方案2】:

我已经测试了以下内容,这确实有效。 gordyii 的答案很接近,但乘以 100 的位置错误,并且缺少括号。

Select Grade, (Count(Grade)* 100 / (Select Count(*) From MyTable)) as Score
From MyTable
Group By Grade

【讨论】:

这给出了整数的结果。结果的总和不等于 100。 不是最有效的,因为表格将被扫描两次。此外,如果引用了多个表,查询看起来也不会那么简单。 @Thunder 您可以将十进制值从 100 更改为 100.0。 有人能解释一下为什么 SQL 查询的数学语法不是您通常期望的那样吗?例如正常我会除以总数然后乘以100?从逻辑的角度来看,我真的对此感到好奇。 @Digitalsa1nt (100 * 2) / 4 = 50, (2/4) * 100 = 50 只要枚举数是被相乘的部分。由于 SQL 语句的优先级,它将是相同的。但是,由于数据类型,如果使用 100,您仍然可以将结果四舍五入到小数点后 0,就像您将它放在除法运算之后一样,您必须确保转换为可以处理的数据类型小数位,否则你最终会得到 100 或 0,而不是实际的百分比【参考方案3】:

您可以使用不带“partition by”子句的窗口函数,而不是使用单独的 CTE 来获取总数。

如果您正在使用:

count(*)

要获取组的计数,您可以使用:

sum(count(*)) over ()

获取总数。

例如:

select Grade, 100. * count(*) / sum(count(*)) over ()
from table
group by Grade;

根据我的经验,它往往更快,但我认为在某些情况下它可能会在内部使用临时表(我在使用“set statistics io on”运行时看到了“Worktable”)。

编辑: 我不确定我的示例查询是否是您要查找的内容,我只是说明了窗口函数的工作原理。

【讨论】:

+1。这很棒。如果用 select 语句代替“table”,也可以使用它。 它在工作台tempdb 中使用了一个线轴。逻辑读取似乎更高but they are counted differently than normal 实际上,查询中的COUNT(*) OVER () 会返回一个完全不相关的数字(具体来说,是分组 结果集的行数)。你应该改用SUM(COUNT(*)) OVER ()【参考方案4】:

我只是在需要计算百分比时使用它..

ROUND(CAST((Numerator * 100.0 / Denominator) AS FLOAT), 2) AS Percentage

请注意,100.0 返回 1 个小数,而 100 本身会将结果四舍五入到最接近的整数,即使使用 ROUND(...,2) 函数也是如此!

【讨论】:

【参考方案5】:

您必须计算总成绩 如果是 SQL 2005 你可以使用 CTE

    WITH Tot(Total) (
    SELECT COUNT(*) FROM table
    )
    SELECT Grade, COUNT(*) / Total * 100
--, CONVERT(VARCHAR, COUNT(*) / Total * 100) + '%'  -- With percentage sign
--, CONVERT(VARCHAR, ROUND(COUNT(*) / Total * 100, -2)) + '%'  -- With Round
    FROM table
    GROUP BY Grade

【讨论】:

当然,这只是给出了表中存在的等级代码的百分比,而不是那些可能存在和不存在的百分比。但是,如果没有相关(有效)等级代码的明确列表,您将无法做得更好。因此,我 +1。 对我来说隐藏的宝石是你注释掉了 CONVERT。【参考方案6】:

您需要在成绩字段上进行分组。这个查询应该给你你在几乎任何数据库中寻找的东西。

    Select Grade, CountofGrade / sum(CountofGrade) *100 
    from
    (
    Select Grade, Count(*) as CountofGrade
    From Grades
    Group By Grade) as sub
    Group by Grade

您应该指定您正在使用的系统。

【讨论】:

既然你在外部选择中有一个聚合 ('sum(CountofGrade)'),你不需要一个 group by 子句吗?在标准 SQL 中,我认为您可以使用 '/ (SELECT COUNT(*) FROM Grades)' 来获得总计。 IBM Informix Dynamic Server 不喜欢选择列表中的裸 SUM(尽管它在抱怨时给出了一些不太有用的消息)。正如我的回答和之前的评论中所指出的,在选择列表中使用完整的子选择表达式在 IDS 中确实有效。 这也更好,因为可以将复杂的 where 应用于内部查询。【参考方案7】:

以下应该可以工作

ID - Key
Grade - A,B,C,D...

编辑:移动 * 100 并添加 1.0 以确保它不会进行整数除法

Select 
   Grade, Count(ID) * 100.0 / ((Select Count(ID) From MyTable) * 1.0)
From MyTable
Group By Grade

【讨论】:

这行得通,但答案都返回为 0 - 我是否需要进行某种数字格式化或转换才能看到正确的答案? Select Grade, round(Count(grade) * 100.0 / ((Select Count(grade) From grades) * 1.0) ,2) From grades Group By Grade在sql-server中添加一个round函数返回例如:21.56000000000【参考方案8】:

我相信这是一个通用的解决方案,尽管我使用 IBM Informix Dynamic Server 11.50.FC3 对其进行了测试。以下查询:

SELECT grade,
       ROUND(100.0 * grade_sum / (SELECT COUNT(*) FROM grades), 2) AS pct_of_grades
    FROM (SELECT grade, COUNT(*) AS grade_sum
            FROM grades
            GROUP BY grade
         )
    ORDER BY grade;

在水平规则下方显示的测试数据上给出以下输出。 ROUND 函数可能是特定于 DBMS 的,但其余的(可能)不是。 (请注意,我将 100 更改为 100.0 以确保使用非整数 - DECIMAL、NUMERIC - 算术进行计算;请参阅 cmets,感谢 Thunder。)

grade  pct_of_grades
CHAR(1) DECIMAL(32,2)
A       32.26
B       16.13
C       12.90
D       12.90
E       9.68
F       16.13

CREATE TABLE grades
(
    id VARCHAR(10) NOT NULL,
    grade CHAR(1) NOT NULL CHECK (grade MATCHES '[ABCDEF]')
);

INSERT INTO grades VALUES('1001', 'A');
INSERT INTO grades VALUES('1002', 'B');
INSERT INTO grades VALUES('1003', 'F');
INSERT INTO grades VALUES('1004', 'C');
INSERT INTO grades VALUES('1005', 'D');
INSERT INTO grades VALUES('1006', 'A');
INSERT INTO grades VALUES('1007', 'F');
INSERT INTO grades VALUES('1008', 'C');
INSERT INTO grades VALUES('1009', 'A');
INSERT INTO grades VALUES('1010', 'E');
INSERT INTO grades VALUES('1001', 'A');
INSERT INTO grades VALUES('1012', 'F');
INSERT INTO grades VALUES('1013', 'D');
INSERT INTO grades VALUES('1014', 'B');
INSERT INTO grades VALUES('1015', 'E');
INSERT INTO grades VALUES('1016', 'A');
INSERT INTO grades VALUES('1017', 'F');
INSERT INTO grades VALUES('1018', 'B');
INSERT INTO grades VALUES('1019', 'C');
INSERT INTO grades VALUES('1020', 'A');
INSERT INTO grades VALUES('1021', 'A');
INSERT INTO grades VALUES('1022', 'E');
INSERT INTO grades VALUES('1023', 'D');
INSERT INTO grades VALUES('1024', 'B');
INSERT INTO grades VALUES('1025', 'A');
INSERT INTO grades VALUES('1026', 'A');
INSERT INTO grades VALUES('1027', 'D');
INSERT INTO grades VALUES('1028', 'B');
INSERT INTO grades VALUES('1029', 'A');
INSERT INTO grades VALUES('1030', 'C');
INSERT INTO grades VALUES('1031', 'F');

【讨论】:

在 sql-server 中给出整数百分比 @Thunder:有趣;如果将 100 更改为 100.00 会发生什么? 确定结果是十进制的100.0【参考方案9】:
SELECT Grade, GradeCount / SUM(GradeCount)
FROM (SELECT Grade, COUNT(*) As GradeCount
      FROM myTable
      GROUP BY Grade) Grades

【讨论】:

【参考方案10】:

在任何 sql server 版本中,您都可以使用一个变量来计算所有成绩的总和,如下所示:

declare @countOfAll decimal(18, 4)
select @countOfAll = COUNT(*) from Grades

select
Grade,  COUNT(*) / @countOfAll * 100
from Grades
group by Grade

【讨论】:

【参考方案11】:

您可以在 from 查询中使用子选择(未经测试,不确定哪个更快):

SELECT Grade, COUNT(*) / TotalRows
FROM (SELECT Grade, COUNT(*) As TotalRows
      FROM myTable) Grades
GROUP BY Grade, TotalRows

或者

SELECT Grade, SUM(PartialCount)
FROM (SELECT Grade, 1/COUNT(*) AS PartialCount
      FROM myTable) Grades
GROUP BY Grade

或者

SELECT Grade, GradeCount / SUM(GradeCount)
FROM (SELECT Grade, COUNT(*) As GradeCount
      FROM myTable
      GROUP BY Grade) Grades

您还可以使用存储过程(对 Firebird 语法表示歉意):

SELECT COUNT(*)
FROM myTable
INTO :TotalCount;

FOR SELECT Grade, COUNT(*)
FROM myTable
GROUP BY Grade
INTO :Grade, :GradeCount
DO
BEGIN
    Percent = :GradeCount / :TotalCount;
    SUSPEND;
END

【讨论】:

【参考方案12】:

我遇到了类似的问题。您应该能够得到乘以 1.0 而不是 100 的正确结果。请参阅附加的示例图片

Select Grade, (Count(Grade)* 1.0 / (Select Count(*) From MyTable)) as Score From MyTable Group By Grade

【讨论】:

除非绝对必要,否则请不要将信息共享为图像。请参阅:meta.***.com/questions/303812/…。【参考方案13】:

这个在 MS SQL 中运行良好。它将 varchar 转换为两位小数限制浮点数的结果。

Select field1, cast(Try_convert(float,(Count(field2)* 100) / 
Try_convert(float, (Select Count(*) From table1))) as decimal(10,2)) as new_field_name 
From table1 
Group By field1, field2;

【讨论】:

以上是关于如何使用 SQL 语句计算百分比的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server中协助计算百分比

SQL:如何使用多列分区计算百分比增加

使用 T-SQL 如何计算考试成绩百分比?

如何在数据透视语句中包含百分比计算

如何使用与计数不同语句相关的百分比创建附加列

如何计算列中的百分比?