У меня есть несколько таблиц, продуктов, входящих и исходящих. Исходящие и входящие имеют две строки, которые дают некоторое представление о том, что происходит, потому что результаты, полученные из запроса, вдвое больше, чем они должны быть
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.
Удаление этой 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 позаботится об этом. Вам нужно будет провести бенчмаркинг.