Вычислить проценты количества в SQL относительно категории

Я работаю в MySQL. Изначально у меня была такая таблица:

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

SELECT
CASE WHEN days_in_waiting_list > (SELECT AVG(days_in_waiting_list) FROM Bookings) THEN 'Long wait'
ELSE 'Short wait' 
END AS waiting, 
is_canceled, COUNT(*), count(*) * 100.0 / sum(count(*)) over() AS perc_cancelled
FROM Bookings
GROUP BY waiting, is_canceled;

Результирующая таблица:

Но я хочу, чтобы проценты рассчитывались для категории, а не для всей таблицы. Чтобы сумма процентов в Коротком ожидании была равна 100, то же самое и в Долгом ожидании. Я хочу, чтобы это было так:

ожидающий is_cancelled проц Короткое ожидание 0 0,61 Короткое ожидание 1 0,39 Долгое ожидание 0 0,32 Долгое ожидание 1 0,68

Есть ли способ сделать это? Я знаю, что можно использовать over (раздел, ожидая), но это дает мне ошибку

Код ошибки: 1054. Неизвестный столбец «ожидает» в «разделе окна»

@Strawberry Извините, я не знал, как это сделать, но я изучу эту тему, спасибо!

Oksana Karacheva 11.12.2020 09:04
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
2
1
1 086
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

вы хотите, чтобы проценты рассчитывались для каждой категории, поэтому для perc_cancelled необходима группировка по категории ожидания

count() * 100.0 / sum(count()) over(partition by wait) КАК perc_cancelled

да, у меня была такая же идея. Но это дает мне ошибку «Неизвестный столбец «ожидает» в «разделе окна»

Oksana Karacheva 11.12.2020 09:03

Я только что попробовал MariaDB 10.5.8, и он отлично работает...

Fabian Pijcke 11.12.2020 13:00
WITH cte AS (
SELECT
CASE WHEN days_in_waiting_list > (SELECT AVG(days_in_waiting_list) FROM Bookings) 
THEN 'Long wait'
ELSE 'Short wait' 
END AS waiting, 
is_canceled,
COUNT(*) as subTotal, 
sum(count(*) over (partition by waiting ORDER BY is_canceled ASC) as totalSum,
FROM Bookings
GROUP BY waiting, is_canceled;
)
SELECT waiting,
is_canceled,
subTotal* (100.0)/totalSum as percentage
FROM cte
group by waiting,is_canceled

Большое спасибо за ваш вклад! Но это показывает мне, что есть синтаксическая ошибка, и я не могу понять, где.

Oksana Karacheva 11.12.2020 10:08

Код ошибки: 1064. У вас ошибка в синтаксисе SQL; проверьте руководство, соответствующее версии вашего сервера MySQL, на предмет правильного синтаксиса для использования рядом с «как общая сумма, промежуточная сумма * (100,0) / общая сумма в процентах ОТ ГРУППА заказов по wai» в строке 7.

Oksana Karacheva 11.12.2020 10:16

можешь попробовать сейчас?

yusuf hayırsever 11.12.2020 10:17
Ответ принят как подходящий

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

select waiting, is_cancelled, 
    count(*) / sum(count(*)) over(partition by waiting) as ratio
from (
    select b.*, 
        case when days_in_waiting_list > avg(days_in_waiting_list) over()
            then 'Long Wait'
            else 'Short wait'
        end as waiting
    from bookings b
) b
group by waiting, is_cancelled
order by waiting, is_cancelled

Я не знаю, почему у меня не работают другие решения, может быть, у меня старая версия MySQL, но это работает!! Большое спасибо :)

Oksana Karacheva 11.12.2020 13:46

Создание таблицы только с соответствующими данными и 40 случайными строками:

CREATE TABLE test (
  id INT AUTO_INCREMENT PRIMARY KEY,
  is_canceled INT DEFAULT FLOOR(RAND() * 2),
  days_in_waiting_list INT DEFAULT FLOOR(RAND() * 100)
);
INSERT INTO test () VALUES (), (), (), (), (), (), (), (), (), ();
INSERT INTO test () VALUES (), (), (), (), (), (), (), (), (), ();
INSERT INTO test () VALUES (), (), (), (), (), (), (), (), (), ();
INSERT INTO test () VALUES (), (), (), (), (), (), (), (), (), ();

Вы были очень близки, просто добавьте PARTITION BY waiting:

SELECT
  CASE WHEN days_in_waiting_list > (
    SELECT AVG(days_in_waiting_list)
    FROM test
  ) THEN 'Long' ELSE 'Short' END AS waiting,
  is_canceled,
  COUNT(*),
  COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY waiting)
FROM test
GROUP BY waiting, is_canceled;
ожидающий is_canceled считать(*) count() / sum(count()) over (раздел с ожиданием) Длинный 0 10 58.82353 Длинный 1 7 41.17647 Короткий 0 15 65.21739 Короткий 1 8 34.78261

Другие вопросы по теме