Использование SUM с Joins в MySQL возвращает неожиданный результат - PullRequest
0 голосов
/ 15 ноября 2018

У меня есть эти таблицы: клиенты , customer_invoices , customer_invoice_details , у каждого клиента много счетов, и в каждом счете много деталей.

Клиент с идентификатором 574413 имеет следующие счета-фактуры:

select customer_invoices.customer_id,
       customer_invoices.id,
       customer_invoices.total_price
from customer_invoices
where customer_invoices.customer_id = 574413;

результат:

customer_id     invoice_id  total_price
574413          662146      700.00
574413          662147      250.00

каждый счет здесь имеет две детали (или строки счета):

первый счет 662146:

select customer_invoice_details.id as detail_id,
       customer_invoice_details.customer_invoice_id as invoice_id,
       customer_invoice_details.total_price as detail_total_price
from customer_invoice_details
where customer_invoice_details.customer_invoice_id = 662146;

результат:

detail_id   invoice_id  detail_total_price
722291      662146      500.00
722292      662146      200.00

второй счет 662147:

select customer_invoice_details.id as detail_id,
       customer_invoice_details.customer_invoice_id as invoice_id,
       customer_invoice_details.total_price as detail_total_price
from customer_invoice_details
where customer_invoice_details.customer_invoice_id = 662147;

результат:

detail_id   invoice_id  detail_total_price
722293      662147      100.00
722294      662147      150.00

У меня проблема с этим запросом:

select customers.id as customerID,
       customers.last_name,
       customers.first_name,
       SUM(customer_invoices.total_price) as invoice_total,
       SUM(customer_invoice_details.total_price) as details_total
from customers
       join customer_invoices
         on customer_invoices.customer_id = customers.id
       join customer_invoice_details
         on customer_invoice_details.customer_invoice_id = customer_invoices.id
where customer_id = 574413;

неожиданный результат:

customerID  last_name   first_name  invoice_total   details_total
574413      terry       amine       1900.00         950.00

Мне нужно иметь SUM из total_price счетов иSUM из total_price деталей для каждого клиента.В этом случае я должен получить 950 как total_price для обоих столбцов (invoice_total & details_total), но это не так.что я делаю не так и как я могу получить правильный результат, пожалуйста.Ответы в похожих темах не имеют решения для этого случая.

Ответы [ 4 ]

0 голосов
/ 15 ноября 2018

Проблема в логике присоединения. Таблица клиентов используется в качестве движущей таблицы в соединениях. Но во втором соединении вы используете столбец производного ключа из первого соединения, чтобы соединиться с третьими таблицами. Это приводит к тому, что декартово выходное значение удваивает записи из результата соединения nth-1, что приводит к повторному повторению customer_invoices.total_price, следовательно, свернутое значение этого поля удваивается. На высоком уровне я чувствую, что цель сворачивания цен уже достигнута в SUM (customer_invoice_details.total_price). Но если у вас есть конкретное требование проекта, чтобы SUM (customer_invoices.total_price) также был получен и соответствовал SUM (customer_invoice_details.total_price), то вы можете сделать это: В отдельном запросе объедините customer_invoice_details и customer_invoices. Сверните поля цены и получите такой результат, что у вас будет только одна запись для одного идентификатора клиента. Затем используйте это как подзапрос и объедините его с таблицей клиентов.

0 голосов
/ 15 ноября 2018

Вы агрегируете по нескольким измерениям.Это сложно.Я бы предложил выполнить агрегирование по каждому измерению независимо:

select c.id as customerID, c.last_name, c.first_name,
       ci.invoice_total,
       cid.details_total
from customers c join
     (select ci.sum(ci.total_price) as invoice_total
      from customer_invoices ci
      group by ci.customer_id
     ) ci
     on ci.customer_id = c.id join
     (select ci.sum(cid.total_price) as details_total
      from customer_invoices ci join
           customer_invoice_details cid
           on cid.customer_invoice_id = ci.id
      group by ci.customer_id
     ) cid
     on cid.customer_id = c.id
where c.id = 574413;

В более быстрой версии (для одного клиента) используются коррелированные подзапросы:

select c.id as customerID, c.last_name, c.first_name,
       (select ci.customer_id, sum(ci.total_price) as invoice_total
        from customer_invoices ci
        where ci.customer_id = c.id 
       ) as invoice_total,
       (select ci.customer_id, sum(cid.total_price) as details_total
        from customer_invoices ci join
             customer_invoice_details cid
             on cid.customer_invoice_id = ci.id
        where ci.customer_id = c.id
       ) as details_total
from customers c 
where c.id = 574413;
0 голосов
/ 15 ноября 2018

Я использовал объединение против подзапросов, а затем сделал сумму на суммы

SELECT c.id as customerID,
   c.last_name,
   c.first_name
   SUM(i.sum) as invoice_total,
   SUM(d.sum) AS details_total
FROM customers c
JOIN (SELECT id, customer_id, SUM(total_price) AS sum
      FROM customer_invoices
      GROUP BY id, customer_id) AS i ON i.customer_id = c.id
JOIN (SELECT customer_invoice_id as id, SUM(total_price) AS sum
      FROM customer_invoice_details 
      GROUP BY customer_invoice_id) AS d ON d.id = i.id
WHERE c.id = 574413
GROUP BY c.id, c.name
0 голосов
/ 15 ноября 2018

Когда вы смешиваете обычные столбцы с агрегатными функциями (например, SUM), вам нужно использовать GROUP BY, где вы перечисляете обычные столбцы из SELECT.

Причина чрезмерного количества в total_price для счетов-фактур заключается в том, что SUM также рассчитывается для каждой строки сведений, поскольку она является частью объединения.Используйте это:

select c.id as customerID,
       c.last_name,
       c.first_name,
       SUM(ci.total_price) as invoice_total,
       SUM((select SUM(d.total_price)
        from customer_invoice_details d
        where d.customer_invoice_id = ci.id)) as 'detail_total_price'
from customers c
       join customer_invoices ci on ci.customer_id = c.id
where c.id = 574413
group by c.id, c.last_name, c.first_name

db-fiddle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...