Home > Software engineering >  Subtracting or Adding data based on logtime of another table
Subtracting or Adding data based on logtime of another table

Time:10-14

So currently I have 2 tables called listings and logs table. The listings table holds a products reference number and it's current status. So suppose if it's status was Publish currently and it's sold, the status updates to Sold. Here the refno. in this table is unique since the status can change for 1 product.

Now I have another table called Logs table, this table records all the status changes that have happened for a particular product(referenced by refno) in a particular timeframe. Suppose the Product with refno. 5 was Publish on 1st October and Sold on 2nd October, The logs table will display as:

Refno status_from status_to logtime
5 Stock Publish 2021-10-01
5 Publish Sold 2021-10-02

This is how my tables currently look like:

Listings table:('D'=>'Draft','N'=>'Action','Y'=>'Publish')

enter image description here

Logs Table which I'm getting using the following statement:

SELECT refno, logtime, status_from, status_to FROM ( 
SELECT refno, logtime, status_from, status_to, ROW_NUMBER() OVER(PARTITION BY refno ORDER BY logtime DESC)
AS RN FROM crm_logs WHERE logtime < '2021-10-12 00:00:00' ) r 
WHERE r.RN = 1 UNION SELECT refno, logtime, status_from, status_to
FROM crm_logs WHERE logtime <= '2021-10-12 00:00:00' AND logtime >= '2015-10-02 00:00:00'
ORDER BY `refno` ASC

enter image description here

The logs table makes a new record every status change made and passes the current timestamp as the logtime, and the listings table changes/updates the status and updates its update_date. Now to get the total listings as of today I'm using the following statement:

SELECT SUM(status_to = 'D') AS draft, SUM(status_to = 'N') AS action, SUM(status_to = 'Y') AS publish FROM `crm_listings`

And this returns all the count data for status as of the current day.

Now this is where it gets confusing for me. So suppose today the count under action is 10 and tomorrow it'll be 15, and I want to retrieve the total that was present yesterday(10). So for this what I would've to do is take todays total(15) and subtract all the places where a product was changed to draft in between yesterday and today(Total count today in listing table - count(*) where status_to='Action' from logs table). Or vice versa, if yesterday it was 10 under action and today it is 5, it should add the values from the status_from column in logs table

Note: Refno isn't unique in my logs table since a product with the same refno can be marked as publish 1 day and unpublish another, but it is unique in my listings table.

Link to dbfiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=01cb3ccfda09f6ddbbbaf02ec92ca894

CodePudding user response:

I am sure it can be simplifed or better. But its my query and logic :

  1. I found status_changes per refno's and calculated total changes from the desired day to present :

select status_logs, sum(cnt_status) to_add from (
SELECT 
status_to as status_logs, -1*count(*) cnt_status
FROM logs lm
where
id = (select max(id) from logs l where l.refno = lm.refno) and 
logtime >= '2021-10-01 00:00:00'
group by status_to
union all 
SELECT 
status_from, count(*) cnt_status_from
FROM logs lm
where
id = (select max(id) from logs l where l.refno = lm.refno) and
logtime >= '2021-10-01 00:00:00'
group by status_from ) total_changes
group by status_logs

  1. I matched the keys between listings table and logs table by converting listings table keys :

select
case status
when 'D' THEN 'Draft'
when 'A' THEN 'Action'
when 'Y' THEN 'Publish'
when 'S' THEN 'Sold'
when 'N' THEN 'Let'
END status_l ,COUNT(*) c
from listings
group by status

  1. I joined them and add the calculations to total sum of current data.

  1. I had to use full outer join , so i have one left and one right join with the same subqueries.

Lastly I used distinct , since it will generate same result for each joined query and used ifnull to bring the other tables status to the other column .

select distinct IFNULL(status_l, status_logs) status, counts_at_2021_10_01
  from (select l.*,
               logs.*,
               l.c   ifnull(logs.to_add, 0) counts_at_2021_10_01
          from (select case status
                         when 'D' THEN
                          'Draft'
                         when 'A' THEN
                          'Action'
                         when 'Y' THEN
                          'Publish'
                         when 'S' THEN
                          'Sold'
                         when 'N' THEN
                          'Let'
                       END status_l,
                       COUNT(*) c
                  from listings
                 group by status) l
          left join (
                    
                    select status_logs, sum(cnt_status) to_add
                      from (SELECT status_to as status_logs,
                                    -1 * count(*) cnt_status
                               FROM logs lm
                              where id = (select max(id)
                                            from logs l
                                           where l.refno = lm.refno)
                                and logtime >= '2021-10-01 00:00:00'
                              group by status_to
                             union all
                             SELECT status_from, count(*) cnt_status_from
                               FROM logs lm
                              where id = (select max(id)
                                            from logs l
                                           where l.refno = lm.refno)
                                and logtime >= '2021-10-01 00:00:00'
                              group by status_from) total_changes
                     group by status_logs) logs
            on logs.status_logs = l.status_l
        union all
        select l.*,
               logs.*,
               l.c   ifnull(logs.to_add, 0) counts_at_2021_05_01
          from (select case status
                         when 'D' THEN
                          'Draft'
                         when 'A' THEN
                          'Action'
                         when 'Y' THEN
                          'Publish'
                         when 'S' THEN
                          'Sold'
                         when 'N' THEN
                          'Let'
                       END status_l,
                       COUNT(*) c
                  from listings
                 group by status) l
         right join (
                    
                    select status_logs, sum(cnt_status) to_add
                      from (SELECT status_to as status_logs,
                                    -1 * count(*) cnt_status
                               FROM logs lm
                              where id = (select max(id)
                                            from logs l
                                           where l.refno = lm.refno)
                                and logtime >= '2021-10-01 00:00:00'
                              group by status_to
                             union all
                             SELECT status_from, count(*) cnt_status_from
                               FROM logs lm
                              where id = (select max(id)
                                            from logs l
                                           where l.refno = lm.refno)
                                and logtime >= '2021-10-01 00:00:00'
                              group by status_from) total_changes
                     group by status_logs) logs
            on logs.status_logs = l.status_l) l
  • Related