2016-07-06 5 views
0

У меня есть таблица поставок и таблицы заказов. Несколько заказов могут быть связаны с доставкой. Несколько дней назад я спросил question о том, как получить сумму суммы заказа за конкретную доставку и быстро показала, как это сделать. (Спасибо еще раз за это.)SUM и GROUP BY вопросы

Теперь мы добавили таблицу расчетов, а также, как и заказы, может быть несколько поселений, связанных с одной доставкой (через идентификатор доставки, точно так же, как с заказами), и я пытаясь получить сумму своих значений. Я полагал, что использую ту же стратегию и LEFT JOIN в таблице расчетов, но проблема в том, что когда есть только одно урегулирование, связанное с конкретной доставкой, SUM (s.amount) возвращает двойное фактическое значение.

Я пробовал играть с GROUP BY безрезультатно. Может ли кто-нибудь показать мне, что я делаю неправильно?

Заранее благодарен!

PS: это вопрос, я с помощью, которая возвращает двойные значения суммы расчетов, когда есть только один населенный пункт:

SELECT 
    d.id, 
    SUM(o.goods_amount) AS amount, 
    SUM(s.amount) AS settlementAmount, 
FROM delivery d 
LEFT JOIN order o 
    ON d.id = o.delivery_id 
LEFT JOIN settlement s 
    ON d.id = s.delivery_id 
WHERE d.id = *deliveryId* 
GROUP BY d.id; 
+0

Наиболее вероятным объяснением является частичный крест продукта. Одна строка от поселения согласовывается с несколькими рядами от доставки и/или заказа. Затем, когда выполняется агрегация, из поселения имеется несколько копий строки. Удалите агрегаты GROUP BY и SUM, запустите запрос, и вы увидите, что происходит. – spencer7593

+0

Я попытался выполнить запрос gthe без GROUP BY AND SUM и был протестирован при поставке с 2 заказами и 1 поселением. Как вы сказали, он возвращает 2 строки, один с order_amount order1 и sett_amount, а другой с order_amount order2 и тот же расчет_база. Поэтому это объясняет, почему СУММ дает мне двойную ценность. Есть ли способ обойти это? – Feanor

+0

Один из подходов - выполнять агрегацию (SUM) из каждой таблицы отдельно, в виде отдельных запросов. Чтобы объединить их, оберните каждый из запросов в parens, а затем используйте весь подзапрос вместо ссылки на таблицу в другом запросе. – spencer7593

ответ

1

Как отметил Спенсер, вы получив своего рода результат перекрестного соединения. Давайте посмотрим на данные примера.

Delivery Table 
ID Delivered_On 
1 2016-07-01 
2 2016-07-02 

Orders Table 
id Deliveries_id Amount 
1 1    100 
2 1    200 
3 1    300 
4 2    75 

Now your Settlements table 
Settlements Table 
id Delivery_id Amount 
1 1    525 (explicitly wrong amount to show result) 
2 1    75 

Ваш запрос делает сумму за Delivery ID, но (слева) присоединился и к таблице заказов и таблице пунктов. Таким образом, столько записей в каждой таблице будет сшито, что для ID доставки = 1, у вас есть 3 заказа, но 1 расчет. Таким образом, запись о поселении будет также соединена с каждой таблицей заказов, а не только с таблицей доставки, что даст результат 3 * 525 или 1575 PLUS 3 * 75 = 225 долларов США в общей сложности 1800 долларов США. Сумма ваших заказов будет равна $ 600.

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

SELECT 
     d.id AS delivery_id, 
     sumOrd.Amount as OrderAmount, 
     sumStl.Amount as SettlementAmount 
    from 
     delivery d 

     LEFT JOIN 
     (select 
       d2.id, 
       SUM(o.amount) AS OrderAmount 
       from 
       delivery d2 
        JOIN order o 
         ON d2.id = o.deliveries_id 
       WHERE 
        d2.delivered_on >= '2016-06-10' 
       and d2.delivered_on < '2016-06-11' 
       GROUP BY 
       d2.id) sumOrd 
      on d.id = sumOrd.id 

     LEFT JOIN 
     (select 
       d2.id, 
       SUM(s.amount) AS SettlementAmount 
       from 
       delivery d2 
        JOIN Settlement s 
         ON d2.id = s.delivery_id 
       WHERE 
        d2.delivered_on >= '2016-06-10' 
       and d2.delivered_on < '2016-06-11' 
       GROUP BY 
       d2.id) sumStl 
      on d.id = sumStl.id 
    where 
      d.delivered_on >= '2016-06-10' 
     and d.delivered_on < '2016-06-11' 
+0

Это трюк, спасибо! – Feanor

0

сначала проверить Ваше получение правильного результата, используя следующий запрос

SELECT 
      d.id, 
      IFNULL(o.goods_amount,0) AS amount, 
      IFNULL(s.amount,0) AS settlementAmount, 
     FROM delivery d 
     LEFT JOIN order o 
      ON d.id = o.delivery_id 
     LEFT JOIN settlement s 
      ON d.id = s.delivery_id 
     WHERE d.id = *deliveryId* 

то пожалуйста, проверьте этот запрос

SELECT 
     d.id, 
     SUM(IFNULL(o.goods_amount,0)) AS amount, 
     SUM(IFNULL(s.amount,0)) AS settlementAmount, 
    FROM delivery d 
    LEFT JOIN order o 
     ON d.id = o.delivery_id 
    LEFT JOIN settlement s 
     ON d.id = s.delivery_id 
    WHERE d.id = *deliveryId* 
    GROUP BY d.id; 
+0

Это дает мне тот же результат, которого я боюсь. Как я написал в комментарии к spencer7593, в случае доставки с 2 заказами и 1 поселением я получаю две записи: одну с суммой из 1-го и 1-го с суммой из 2-го порядка, но у них обоих есть расчет.: -/ – Feanor

+0

@Feanor вы проверили с 1-м запросом и можете добавить этот набор результатов –

+0

sure Запись 1: id: 7887, количество: 15.80, расчетное количество: 19.08 Запись 2: id: 7887, количество: 9.00, расчетное количество: 19.08 – Feanor