Как рассчитать процент с помощью оператора SQL

У меня есть таблица SQL Server, содержащая пользователей и их оценки. Для простоты просто скажем, что есть 2 столбца - name и grade. Таким образом, типичная строка будет Name: "John Doe", Grade: "A".

Я ищу один оператор SQL, который найдет процент всех возможных ответов. (A, B, C и т.д.) Кроме того, есть ли способ сделать это без определения всех возможных ответов (открытое текстовое поле - пользователи могут вводить "pass/fail", "none" и т.д.)

Конечный результат, который я ищу, составляет A: 5%, B: 15%, C: 40% и т.д.

Ответ 1

Я тестировал следующее, и это работает. Ответ от gordyii был близок, но имел умножение 100 в неправильном месте и имел некоторые отсутствующие круглые скобки.

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

Ответ 2

  • Самый эффективный (с использованием функции over()).

    select Grade, count(*) * 100.0 / sum(count(*)) over()
    from MyTable
    group by Grade
    
  • Универсальная (любая версия SQL).

    select Rate, count(*) * 100.0 / (select count(*) from MyTable)
    from MyTable
    group by Rate;
    
  • С CTE наименее эффективным.

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

Ответ 3

Вместо того, чтобы использовать отдельный CTE для получения общего значения, вы можете использовать функцию окна без предложения "partition by".

Если вы используете:

count(*)

чтобы получить счетчик для группы, вы можете использовать:

sum(count(*)) over ()

чтобы получить общее количество.

Например:

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

В моем опыте он работает быстрее, но я думаю, что в некоторых случаях он мог бы использовать временную таблицу (я видел "Рабочую таблицу" при работе с "set statistics io on" ).

EDIT: Я не уверен, что мой примерный запрос - это то, что вы ищете, я просто иллюстрировал работу оконных функций.

Ответ 4

Вы должны рассчитать общее количество оценок Если это 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

Ответ 5

Вам нужно сгруппировать в поле оценки. Этот запрос должен дать вам то, что вы ищете в почти любой базе данных.

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

Вы должны указать используемую вами систему.

Ответ 6

Я просто использую это, когда мне нужно проработать процент.

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

Обратите внимание, что 100.0 возвращает десятичные числа, тогда как 100 на нем будут округлять результат до ближайшего целого числа, даже с помощью функции ROUND()!

Ответ 7

Следующее должно работать

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

EDIT: Перемещено * 100 и добавлено 1.0, чтобы убедиться, что он не выполняет целочисленное деление

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

Ответ 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 может быть специфичной для СУБД, но остальная часть (вероятно) не является. (Обратите внимание, что я изменил 100 на 100.0, чтобы убедиться, что вычисление происходит с использованием нецелого числа - DECIMAL, NUMERIC - арифметика, см. Комментарии и спасибо 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');

Ответ 9

В любой версии sql-сервера вы можете использовать переменную для всех классов, таких как:

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

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

Ответ 10

Вы можете использовать подзапрос в своем запросе (непроверенный и не уверен, что быстрее):

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

Ответ 11

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