MySQL - процентное увеличение на основе нескольких столбцов не работает - PullRequest
0 голосов
/ 17 марта 2019

Я пытаюсь написать запрос, который рассчитывает процентное увеличение на основе трех столбцов A1, A2, A3. Цель состоит в том, чтобы определить процент увеличения / уменьшения. Пожалуйста, смотрите упрощенные расчеты Excel

enter image description here

Здесь A1, A2, A3 - три столбца в моей таблице PCLS, с помощью которых я обновляю таблицу PCNT. Вычисления просты, я сначала посчитал, сколько раз PCNT появляется. A появляется в столбцах A1, A2, A3 (в данном случае 4,52,3), затем применяю коэффициент 10000, чтобы получить начальное значение в столбце S10K. Столбец CV извлекает текущее значение из другого источника, теперь моя цель - определить% увеличения или уменьшения CV по сравнению с S10K. В примере Excel это будет (630135.6-590000) / (590000) * 100, что соответствует увеличению на 6,80%. В Excel это выглядит просто, но я не могу заставить его правильно рассчитать в MySQL. Я попробовал следующее

UPDATE PCNT SET `R%`= (
    (
        (
            (
                (SELECT SUM(`CV`) from PCLS WHERE `A1`=PCNT.`A`) 
                + (SELECT SUM(`CV`) from PCLS WHERE `A2`=PCNT.`A`) 
                + (SELECT SUM(`CV`) from PCLS WHERE `A3`=PCNT.`A`)
            ) 
            - (
                (
                    (SELECT count(`CV`) from PCLS WHERE `A1`=PCNT.`A`)
                    + (SELECT count(`CV`) from PCLS WHERE `A2`=PCNT.`A`)
                    + (SELECT count(`CV`) from PCLS WHERE `A3`=PCNT.`A`)
                )*10000
            )
        )
    ) 
    / 
    (
        (
            (SELECT count(`CV`) from PCLS WHERE `A1`=PCNT.`A`)
            + (SELECT count(`CV`) from PCLS WHERE `A2`=PCNT.`A`)
            + (SELECT count(`CV`) from PCLS WHERE `A3`=PCNT.`A`)
        ) * 10000
    )
)*100;

Однако, похоже, это работает только тогда, когда PCNT. A присутствует во всех трех столбцах A1, A2, A3. Если он не присутствует ни в одном из столбцов, он оценивается как NULL.

Я попробовал следующую альтернативу, но проблема не исчезла

UPDATE PCNT
set `R%` = ((((((SELECT SUM(`CV`) from PCLS WHERE `A1`=PCNT.`A`) - ((SELECT 
count(`CV`) from PCLS WHERE `A1`=PCNT.`A`)*10000))/((SELECT count(`CV`) from 
PCLS WHERE `A1`=PCNT.`A`)*10000))*100))) + ((((((SELECT SUM(`CV`) from PCLS 
WHERE `A2`=PCNT.`A`) - ((SELECT count(`CV`) from PCLS WHERE 
`A2`=PCNT.`A`)*10000))/((SELECT count(`CV`) from PCLS WHERE 
`A2`=PCNT.`A`)*10000))*100))) + ((((((SELECT SUM(`CV`) from PCLS WHERE 
`A3`=PCNT.`A`) - ((SELECT count(`CV`) from PCLS WHERE 
`A3`=PCNT.`A`)*10000))/((SELECT count(`CV`) from PCLS WHERE 
`A3`=PCNT.`A`)*10000))*100)));

Если я воспользуюсь приведенным ниже запросом, ограничив поиск только столбцом A1, все будет работать нормально. Этот запрос оценивается в 16,34% аналогично тому, что видно на скриншоте Excel.

UPDATE PCNT
set `R%` = (((SELECT SUM(`CV`) from PCLS WHERE `A1`=PCNT.`A`) - ((SELECT 
count(`CV`) from PCLS WHERE `A1`=PCNT.`A`)*10000))/((SELECT count(`CV`) from 
PCLS WHERE `A1`=PCNT.`A`)*10000))*100;

На данный момент я включаю A2 и A3 любые значения PCNT. A, которых нет в A1, A2 оценивается как NULL. Все, что я хочу, это запрос на возврат (630135.6-590000) / (590000) * 100 = 6,80%, но мне трудно заставить его работать. Я чувствую, что операция сложения вызывает проблему.

Есть ли правильный или альтернативный способ сделать это. Я пытался сделать несколько изменений, но не увенчался успехом.

SELECT SUM(`CV`) from PCLS WHERE `A1`=PCNT.`A`
SELECT COUNT(`CV`) from PCLS WHERE `A1`=PCNT.`A`

Приведенные выше два запроса, если они работают автономно, проблема возникает, когда я использую оператор сложения.

1 Ответ

1 голос
/ 17 марта 2019

На данный момент я включаю A2 и A3 любые значения PCNT.A, которые отсутствуют в A1, A2 оцениваются как NULL.[...] Я чувствую, что операция сложения вызывает проблему.

Добавление, где один из членов равен NULL, возвращает NULL (то же самое относится и к другим арифметическим операциям).Вам нужно заключить подзапросы в COALESCE(), чтобы вместо них было возвращено 0.

Итог, я подозреваю, что ваш запрос можно переписать, чтобы заменить множественные встроенные запросы на LEFT JOIN s на агрегированныхподзапросы, например:

UPDATE pcnt pn
LEFT JOIN (SELECT a1, SUM(cv) sumcv, COUNT(cv) cntcv FROM pcls GROUP BY a1) pa1 ON pa1.a1 = pn.a
LEFT JOIN (SELECT a2, SUM(cv) sumcv, COUNT(cv) cntcv FROM pcls GROUP BY a2) pa2 ON pa2.a2 = pn.a
LEFT JOIN (SELECT a3, SUM(cv) sumcv, COUNT(cv) cntcv FROM pcls GROUP BY a3) pa3 ON pa3.a3 = pn.a
SET pn.`R%` = 
    ( 
        COALESCE(pa1.sumcv, 0) + COALESCE(pa2.sumcv, 0) + COALESCE(pa3.sumcv, 0)
        - (COALESCE(pa1.cntcv, 0) + COALESCE(pa2.cntcv, 0) + COALESCE(pa3.cntcv, 0)) * 10000
    ) 
    / ((COALESCE(pa1.cntcv, 0) + COALESCE(pa2.cntcv, 0) + COALESCE(pa3.cntcv, 0)) * 10000)
    * 100
...