phpmysqlcodeigniterjoinsql-update

MySql - Update the status of rows using FIFO logic


I've the below mysql table where I want to update multiple rows of approval_status field with 1 if the quantity passed is more than the qty_req value using MySql or PHP.

Requisition table:

id part_id qty_req approval_status
1 16 20 0
2 17 30 0
3 16 40 0
4 17 50 0
5 17 60 0

Example:

$update_status=Array ( 
    [0] => Array ( [part_id] => 17 [qty] => 90 )
    [1] => Array ( [part_id] => 16 [qty] => 70 ) 
)

From the above array, 90 is the quantity available for the part_id 17. I want to update the approval_status as 1 in the requisition table for the rows with the part_id as 17 with the below scenario:

  1. Update the approval_status to 1 as the quantity of the first row with part_id 17 is 30 which is less than 90.

  2. Update the approval_status to 1 as the quantity of the second row with part_id 17 is 30+50=80 which is less than 90.

  3. Third row won't update as the total 30+50+60=140 is greater than 90.

Unfortunately, I couldn't find any tutorial to achieve this.

Any help would be appreciated. Thanks in advance.


Solution

  • Single data:

    UPDATE test t1
    NATURAL JOIN ( SELECT *, SUM(qty_req) OVER (ORDER BY reg_date) cum_sum
                   FROM test
                   WHERE part_id = @part_id ) t2
    SET t1.approval_status = 1 
    WHERE cum_sum <= @qty;
    

    Multiple data:

    UPDATE test t1
    NATURAL JOIN ( SELECT test.*, 
                          SUM(qty_req) OVER (PARTITION BY part_id ORDER BY reg_date) cum_sum,
                          qty
                   FROM test
                   JOIN JSON_TABLE(@json,
                                   '$[*]' COLUMNS ( part_id INT PATH '$.part_id',
                                                    qty INT PATH '$.qty')) jsontable USING (part_id) ) t2
    SET t1.approval_status = 1 
    WHERE cum_sum <= qty;
    

    https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=7cf062d81a138657dee78f3026623783

    Column reg_date and unique index added for to provide definite and unambiguous rows ordering.


    The solution applicable to MySQL 5.6:

    UPDATE test t1
    NATURAL JOIN ( SELECT t1.part_id,
                          t1.qty_req,
                          t1.approval_status,
                          t1.reg_date,
                          SUM(t2.qty_req) cum_sum
                   FROM test t1
                   JOIN test t2 USING (part_id)
                   WHERE t1.reg_date >= t2.reg_date
                   GROUP BY t1.part_id,
                            t1.qty_req,
                            t1.approval_status,
                            t1.reg_date ) t2
    JOIN ( SELECT 17 part_id, 90 qty
           UNION ALL
           SELECT 16, 50 ) t3 USING (part_id)
    SET t1.approval_status = 1 
    WHERE t2.cum_sum <= t3.qty
    

    https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=0aad358941f66d1f385799072237d513

    Source data must be formed as a query text - see subquery t3.