Question

I have a log table with several statuses. It logs the position of physical objects in an external system. I want to get the latest rows for a status for each distinct physical object.

I need a list of typeids and their quantity for each status, minus the quantity of typeids that have an entry for another status that is later than the row with the status we are looking for.

e.g each status move is recorded but nothing else.

Here's the problem, I don't have a distinct ID for each physical object. I can only calculate how many there are from the state of the log table.

I've tried

    SELECT dl.id, dl.status
    FROM  `log` AS dl
    INNER JOIN (
      SELECT MAX(  `date` ) , id
      FROM  `log` 
      GROUP BY id ORDER BY `date` DESC 
    ) AS dl2
    WHERE dl.id = dl2.id

but this would require a distinct type id to work.

My table has a primary key id, datetime, status, product type_id. There are four different statuses.

a product must pass through all statuses.

Example Data.

date       typeid status    id

2014-01-13 PF0180 shopfloor 71941
2014-01-13 ND0355 shopfloor 71940
2014-01-10 ND0355 machine   71938
2014-01-10 ND0355 machine   71937
2014-01-10 ND0282 machine   7193

when selected results for the status shopfloor I would want

quantity typeid
1        ND0355
1        PF0180

when selecting for status machine I would want

quantity typeid
1        ND0282
1        ND0355

The order of the statuses shouldn't matter it only matters if there is a later entry for the product.

Was it helpful?

Solution

If I understood you correctly, this will give you the desired output:

select
  l1.typeid, 
  l1.status, 
  count(1) - (
    select count(1)
    from log l2
    where l2.typeid = l1.typeid and
          l2.date > l1.date
  )
from log l1
group by l1.typeid, l1.status;

Check this SQL Fiddle

TYPEID  STATUS      TOTAL
-----------------------------
ND0282  machine     1
ND0355  machine     1
ND0355  shopfloor   1
PF0180  shopfloor   1

OTHER TIPS

You need to get the greatest date per status, not per id. Then join to the log table where the status and date are the same.

SELECT dl.id, dl.status
FROM  `log` AS dl
INNER JOIN (
  SELECT status, MAX(  `date` ) AS date
  FROM  `log` 
  GROUP BY status ORDER BY NULL
) AS dl2 USING (status, date);

It would be helpful to have an index on (status, date) on this table, which would allow the subquery to run as an index-only query.

Everton Agner originally posted this solution, but the reply seems to have disappeared so I'm adding it (with slight modifications)

select
  l1.typeid, 
  l1.status, 
  count(1) - (
    select count(1)
    from log l2
    where l2.typeid = l1.typeid and
          l2.`date` > l1.`date`
          AND l2.status != 'dieshop'
  ) as quant
from log l1
WHERE l1.status = 'dieshop' 
group by l1.typeid;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top