2

Case:

I select an initial date and an end date, it should bring me the movements of all the products in that date range, but if there were movements before the initial date (records in table), I want to obtain the previous sum (prevData)

If the first move is exit 5 and the second move is income 2.

I would have in the first row (prevData-5), second row would have (prevData-5 + 2) and thus have a cumulative.

The prevData would be calculated as the sum of the above, validating the product id of the record, I made the query but if the product has 10 movements, I would do the query 10 times, and how would I identify the sum of another product_id?

SELECT
ik.id,
ik.quantity,
ik.date,
ik.product_id,
#balance = (SELECT SUM(quantity) FROM table_kardex WHERE product_id = ik.product_id AND id < ik.id)
from table_kardex  ik
where ik.date between '2021-11-01'  and  '2021-11-15'
order by ik.product_id,ik.id asc

I hope you have given me to understand, I will be attentive to any questions.

table_kardex

id quantity date product_id
1 8 2020-10-12 2
2 15 2020-10-12 1
3 5 2021-11-01 1
4 10 2021-11-01 2
5 -2 2021-11-02 1
6 -4 2021-11-02 2

is the total sum(quantity) that is less than the id of that record obviously with the same product_id, for the example the id 1 and 2 would be the prev data

result

id|quantity|date|product_id|balance
3  5       2021-11-01  1    20  (15+5)
5  -2      2021-11-02  1    18  (15+5-2)
4  10      2021-11-01  2    18  (8+10)
6  -4      2021-11-02  2    14  (18-4)

It can be done with a normal query, or using a view or cursors, maybe you could guide me, I have changed to MySQL 8.

5
  • What is precise MySQL version? PS. provide sample data as CREATE TABLE + INSERT INTO scripts (or as online fiddle).
    – Akina
    Commented Jan 13, 2022 at 5:46
  • Is there a reason you are using this old MySQL version? Upgrade if you can. Commented Jan 13, 2022 at 6:01
  • @ThorstenKettner sharing a database for a system in C #, compatibility problem I understand that it could arise
    – DarkFenix
    Commented Jan 13, 2022 at 6:03
  • 1
    Well, usually the newer the versions the less problems. But, yes, if your C# version is as outdated as your MySQL version, you might have to upgrade both. In my opinion, though, it is usually worth it having your software up-to-date. Commented Jan 13, 2022 at 6:13
  • What is a movement here is not explained. What is meant by "if the first move is exit 5 and the second move is income 2.". How many different moves are there and as stated earlier what is a move. In your example why for product id 2 you have 14 as an answer when 15+5-2 is equal to 18 and how did you get 14 or 18 for product id 2 . Nothing is clear
    – Harpreet
    Commented Mar 8, 2023 at 16:15

3 Answers 3

1

If you're using MySQL 8+, then analytic functions can be used here:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY date) rn,
              SUM(quantity) OVER (PARTITION BY product_id ORDER BY date) saldo
    FROM table_kardex
    WHERE date BETWEEN '2021-11-01' AND '2021-11-15'
)

SELECT id, quantity, date, product_id, saldo
FROM cte
WHERE rn > 1
ORDER BY product_id, date;
1
  • I have switched to MySQL 8. but this query does not get the corresponding balance prior to the start date
    – DarkFenix
    Commented Feb 28, 2023 at 23:39
1

MySQL 5.7

Try this:

SELECT *
FROM (
    SELECT product_id, 
           t1.`date`, 
           SUM(t2.quantity) - t1.quantity cumulative_quantity_before, 
           SUM(t2.quantity) cumulative_quantity_after
    FROM table t1
    JOIN table t2 USING (product_id)
    WHERE t1.`date` >= t2.`date`
      AND t1.`date` <= @period_end
    GROUP BY product_id, t1.`date`, t1.quantity
) prepare_data
WHERE `date` >= @period_start;
1

The easiest solution is to use the window function SUM OVER to get the running total. In the second step reduce this to the date you want to have this started:

SELECT id, quantity, date, product_id, balance
FROM
(
    SELECT
      id,
      quantity,
      date,
      product_id,
      SUM(quantity) OVER (PARTITION BY product_id ORDER BY id) AS balance
    from table_kardex ik
    where date < DATE '2021-11-16'
) cumulated
WHERE date >= DATE '2021-11-01'  
ORDER BY product_id, id;

UPDATE: You have changed your request to mention that you are using an old MySQL version (5.7). This doesn't support window functions. In that case use your original query. If I am not mistaken, though, #balance = (...) is invalid syntax for MySQL. And according to your explanation you want id <= ik.id, not id < ik.id:

SELECT
  ik.id,
  ik.quantity,
  ik.date,
  ik.product_id,
  (
    SELECT SUM(quantity)
    FROM table_kardex 
    WHERE product_id = ik.product_id AND id <= ik.id
  ) AS balance
FROM table_kardex ik
WHERE ik.date >= DATE '2021-11-01' AND ik.date < DATE '2021-11-16'
ORDER BY ik.product_id, ik.id;

The appropriate indexes for this query are:

create index idx1 on table_kardex (date, product_id, id);
create index idx2 on table_kardex (product_id, id, quantity);
2
  • In your second answer, is what I try to avoid, it takes too long to process since for each row it redoes the sum, if I have 10 records of the product_id, it processes 10 times the sum of the previous balance. The MySQL I have not tried because I use 5.6
    – DarkFenix
    Commented Jan 13, 2022 at 6:01
  • If you must use this old MySQL version, I think this is the most appropriate query though. You can muddle through with variables, but I usually don't recommend this. Make sure you have helpful indexes provided. I've updated my answer with my index recommendation. Commented Jan 13, 2022 at 6:04

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.