Question

My table "orders" includes the date_purchased and my table "orders_products" includes the products_id for the specific order.

I want to list a specific client's all purchased products_id (not all orders!) showing the latest date_purchased for each products_id. The list should be ordered with the latest orders_id of these at the top.

The code below will show all unique products_id as I want, but the "group by" is resulting in not showing the latest orders_id or date_purchased for each products_id…

What am I missing here?

SELECT o.orders_id, o.date_purchased, op.products_id

FROM orders o, orders_products op

WHERE o.customers_id = '" . $client_id . "' and op.orders_id = o.orders_id

GROUP BY op.products_id
ORDER BY orders_id DESC
Was it helpful?

Solution

The not exists approach is often the most efficient approach for this type of query:

SELECT o.orders_id, o.date_purchased, op.products_id 
FROM orders o join
     orders_products op
     on op.orders_id = o.orders_id
WHERE o.customers_id = '" . $client_id . "' and 
      not exists (select 1
                  from orders o2 join
                       orders_products op2
                       on op2.orders_id = o2.orders_id
                  where op2.products_id = op.products_id and
                        o.customers_id = '" . $client_id . "' and
                        o2.orders_id > o.orders_id
                 )
ORDER BY orders_id DESC;

The logic is: "Get me all rows from orders where there is no row with the same product and a larger id." This is equivalent to saying: "Get me the max row".

For best performance, you want an index on orders(products_id, orders_id).

EDIT:

There is another approach that uses subtring_index() and group_concat(). This might be the most efficient way, if the filter on customer_id is highly selective (that is, greatly reduces the number of rows).

SELECT max(o.orders_id) as orders_id,
       substring_index(group_concat(o.date_purchased order by orders_id desc), ',', 1) as date_purchased,
       op.products_id 
FROM orders o join
     orders_products op
     on op.orders_id = o.orders_id
WHERE o.customers_id = '" . $client_id . "'
GROUP BY op.products_id;

Of course, if the date purchased and orders_id are both increasing, you can simplify this to using max() for both:

SELECT max(o.orders_id) as orders_id,
       max(o.date_purchased) as date_purchased,
       op.products_id 
FROM orders o join
     orders_products op
     on op.orders_id = o.orders_id
WHERE o.customers_id = '" . $client_id . "'
GROUP BY op.products_id;

OTHER TIPS

Using group by the result will be grouped in un-ordered way you cannot rely on that using group by will give you the latest result in each so for this you need to first get the maximum of purchase date and then join with your orders table with using additional condition in on clause

SELECT 
  o.orders_id,
  o.date_purchased,
  oo.products_id 
FROM
  orders o
  INNER JOIN (
  SELECT orders.orders_id, MAX(orders.date_purchased) date_purchased ,orders_products.products_id
  FROM orders 
  INNER JOIN   
  orders_products  
  ON(orders_products.orders_id = orders.orders_id)
  GROUP BY orders.orders_id ,orders_products.products_id
  ) oo
   ON( oo.orders_id = o.orders_id AND oo.date_purchased=o.date_purchased)
WHERE o.customers_id = '" . $client_id . "'    
ORDER BY o.orders_id DESC  

This will give the latest orders per products of customer

You might try this? Cannot test it right now.

SELECT MAX(o.orders_id), MAX(o.date_purchased), op.products_id

FROM orders o, orders_products op

WHERE o.customers_id = 1 and op.orders_id = o.orders_id

GROUP BY op.products_id
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top