Bram
Bram

Reputation: 2580

SQL query left join where clause

This is my situation.

I have 3 tables

Orders
 - id  status deleted

Order Lines
 - related_id related_model quantity

Products
 - id  code  price  price_purchase

I want to create a list with all products. The amount of times they are purchased and a sum of the gross margin (price - price_purchase). It must only use orders lines with the related model set to 'products'. And secondly it must only pick orders with the status set to 'paid, processing, sent, ready_for_pickup or picked_up' and with the order not deleted.

So this would be the result I want:

id | code  | purchases | value
-------------------------------
1  | code1 | 7         | 57,05
2  | code2 | 122       | 254,98
3  | code3 | 0         | 0,00

This is the SQL query I have so far:

SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,     
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id 
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id 

WHERE so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0  
GROUP BY p.id

It returns the correct data. But not all problems. That is my problem. I a lot of different methods like sub queries and other methods but can't seem to solve the problem. I know the problem is my LEFT join, but don't know a solution to my problem.

I'm using MySQL Workbench.

Any help is welcome.

Upvotes: 0

Views: 115

Answers (2)

John Bollinger
John Bollinger

Reputation: 181824

Your joins are wrong. You need to identify the order lines to consider separately from and prior to forming the LEFT JOIN with the product details. An inline view could help:

  SELECT
    p.id,
    p.code,
    IFNULL(SUM(ordered_item.quantity) , 0) as purchases ,     
    sum((p.price - p.price_purchase) * ordered_item.quantity) as value
  FROM
   products p
   LEFT JOIN (
      SELECT
        sol.related_id AS related_id,
        sol.quantity AS quantity
      FROM
        shop_orders_lines sol
        INNER JOIN shop_orders so
          ON so.id = sol.order_id
      WHERE
        so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
          AND so.deleted = 0
          AND sol.related_model = 'products'  
    ) ordered_item
      ON ordered_item.related_id = p.id
GROUP BY p.id

Upvotes: 2

jarlh
jarlh

Reputation: 44795

Move outer table conditions from WHERE to ON, otherwise the OUTER JOIN works like a regular INNER JOIN:

SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,     
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id 
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id AND
so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
GROUP BY p.id

Is p.id the whole primary key for that table? If not, you need to find out how to treat p.code. (Either list in GROUP BY, or use as argument to aggregate function.)

Another try:

SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,     
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
JOIN shop_orders_lines sol ON sol.related_id = p.id 
AND sol.related_model = 'products'
WHERE EXISTS (select 1 from shop_orders so
              where so.id = sol.order_id
                AND so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
                AND so.deleted = 0)
GROUP BY p.id

Upvotes: 1

Related Questions