Skip to content

Instantly share code, notes, and snippets.

@hossam-fares
Last active October 29, 2015 14:51
Show Gist options
  • Save hossam-fares/51a554965e98547d77d6 to your computer and use it in GitHub Desktop.
Save hossam-fares/51a554965e98547d77d6 to your computer and use it in GitHub Desktop.

Dear guys,

This week I was facing this problem:

In agent zero we want to select the order along with the latest payment status and since order may have one or more payment status things was kinda tricky.

So first I write the query and select all payment status for the order like:

 SELECT so.order_nr, sop.id_sop, sop.status 
 FROM sales_order so 
 LEFT JOIN sales_order_payment sop ON so.id_so = sop.fk_so;

Which results:

order_nr id_sop status
AE1234 12 waiting approval
AE1234 14 on progress
AE1234 16 Successfull

But I need only the last result:

order_nr id_sop status
AE1234 16 Successfull

So first idea to solve this problem was using MAX() function like:

 SELECT so.order_nr, MAX(sop.id_sop), sop.status 
 FROM sales_order so 
 LEFT JOIN sales_order_payment sop ON so.id_so = sop.fk_so;

But I was getting invalid status while the id_sop was the max:

order_nr id_sop status
AE1234 16 on progress

The seconed idea to use subquery like:

 SELECT so.order_nr, sop.id_sop, sop.status 
 FROM sales_order so 
 LEFT JOIN (
  SELECT id_sop, status
  FROM sales_order_payment
  group by fk_sales_order
  order by id_sales_order_payment desc
 ) sop ON so.id_so = sop.fk_so;

that one worked but the joining with query has a huge impact in the performanse and the query processing time was huge

After a lot of search I found one nice soultion in stackoverflow

 SELECT so.order_nr, sop.id_sop, sop.status 
 FROM sales_order so 
 LEFT JOIN sales_order_payment sop ON so.id_so = sop.fk_so
 LEFT JOIN sales_order_payment sop2 ON sop2.fk_so = sop.fk_so AND sop.id_sop < sop2.id_sop
 WHERE sop2.id_sop IS NULL;

Thats solve the issue and performance was great, but it's kinda complex, right?

Lets try to analyze it:

So we did a self join to sales_order_payment but the joining conditions is sop2.fk_so = sop.fk_so AND sop.id_sop < sop2.id_sop which means: for each result get all sop2 rows that have the same order number and it's id is lower than the sop1 Id

 SELECT so.order_nr, sop.id_sop, sop.status, sop2.id_sop 
 FROM sales_order so 
 LEFT JOIN sales_order_payment sop ON so.id_so = sop.fk_so
 LEFT JOIN sales_order_payment sop2 ON sop2.fk_so = sop.fk_so AND sop.id_sop < sop2.id_sop;

Thats will give us an output like:

order_nr id_sop status id_sop
AE1234 12 waiting approval 14
AE1234 12 waiting approval 16
AE1234 14 on progress 16
AE1234 16 Successfull null

Then we add a where condition WHERE sop2.id_sop IS NULL to get only the greatest sop.id_sop value from the result set

 SELECT so.order_nr, sop.id_sop, sop.status 
 FROM sales_order so 
 LEFT JOIN sales_order_payment sop ON so.id_so = sop.fk_so
 LEFT JOIN sales_order_payment sop2 ON sop2.fk_so = sop.fk_so AND sop.id_sop < sop2.id_sop
 WHERE sop2.id_sop IS NULL;

and finally we got the correct resut:

order_nr id_sop status
AE1234 16 Successfull
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment