SUM () возвращает неправильные значения

0

У меня есть несколько таблиц, продуктов, входящих и исходящих. Исходящие и входящие имеют две строки, которые дают некоторое представление о том, что происходит, потому что результаты, полученные из запроса, вдвое больше, чем они должны быть

SELECT products.ProductName, products.StartingInventory,
        sum(incoming.NumReceived) invReceived, sum(outgoing.NumberShipped) invShipped,
        products.InventoryOnHand, products.MinimumRequired 
from incoming, products, outgoing 
where incoming.ProductId = products.id and outgoing.ProductId = products.id 
group by products.id

Эти два значения являются invReceived и invShipped. Это входящая таблица:

| id  SupplierID ProductID NumReceived PurchaseDate |
| 1   1          1         6           2018-02-01   |
| 2   1          1         7           2017-05-09   |

и исходящей таблицы

|id First    Middle    Last        ProductId NumberShipped OrderDate |
|1  Dan      Smith     Agent       1         6             2018-02-01|
|2  Bethany  Richards  Richardson  1         15            2018-04-20|

Результат invReceived: 26 и invShipped 36, но должно быть 13 и 18.

  • 1
    Использование явных JOINs является стандартным, принятым стилем; неявные нотации «запятые» объединяются десятилетиями, так как их сложнее читать и поддерживать.
Показать ещё 8 комментариев
Теги:
sum

1 ответ

1
Лучший ответ

Удаление этой group by совокупности функций (т. sum) выявляет проблему.

sqlite> SELECT products.ProductName, products.StartingInventory,
   ...>         incoming.NumReceived invReceived, outgoing.NumberShipped invShipped,
   ...>         products.InventoryOnHand, products.MinimumRequired 
   ...> from incoming, products, outgoing 
   ...> where incoming.ProductId = products.id and outgoing.ProductId = products.id 
   ...> 
   ...> ;
ProductName  StartingInventory  invReceived  invShipped  InventoryOnHand  MinimumRequired
-----------  -----------------  -----------  ----------  ---------------  ---------------
Dell         290                6            3           300              10             
Dell         290                7            3           300              10             
Dell         290                6            15          300              10             
Dell         290                7            15          300              10    

(Я делаю это в SQLite, но от MySQL не должно быть разницы).

Строки подсчитываются дважды. Мы можем видеть проблему более ясной, просто выбрав идентификаторы.

sqlite> SELECT products.id, incoming.id, outgoing.id
   ...> from incoming, products, outgoing 
   ...> where incoming.ProductId = products.id and outgoing.ProductId = products.id 
   ...> ;
id          id          id        
----------  ----------  ----------
1           1           1         
1           2           1         
1           1           2         
1           2           2         

Есть несколько способов решить эту проблему. Один из них - @JerryJermiah в комментариях.

SELECT products.id, 
    (select sum(incoming.NumReceived)
     from incoming
     where incoming.productid = products.id),
    (select sum(outgoing.NumberShipped)
     from outgoing
     where outgoing.productid = products.id)
from products;

Он извлекает каждый продукт один раз и затем выполняет подвыбор на каждом продукте, чтобы получить NumReceived и NumberShipped.

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

select p.id, ig.NumReceived, og.NumShipped
from products p
join (
    select productid, sum(NumReceived) as NumReceived
    from incoming
    group by productid
) as ig on p.id = ig.productid
join (
    select productid, sum(NumberShipped) as NumShipped
    from outgoing
    group by productid
) as og on p.id = og.productid

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню