Adding the rows of a column into another column per row - mysql

I'm trying to create a query that creates a column that adds all the row value of the previous column per row. I've tried SUM and COUNT but this is not giving me the result I want. How should I tackle this problem?
+----+------+-----+
| id |amount|total|
+----+------+-----+
| 1 | 10 | 10 |
| 2 | 20 | 30 |
| 3 | 15 | 45 |
| 4 | 30 | 75 |
+----+------+-----+

It is a Rolling Sum problem. In MySQL 8.0.2 and above, you can solve this using Window functions with Frames. In older versions, we can do the same using User-defined Session variables.
Try:
SELECT
dt.id,
dt.amount,
#tot := #tot + dt.amount AS total
FROM
(
SELECT
id,
amount
FROM your_table_name
ORDER BY id
) AS dt
CROSS JOIN (SELECT #tot := 0) AS user_init

Related

SQL Query with all data from lest column and fill blank with previous row value

After searching a lot on this forum and the web, i have an issue that i cannot solve without your help.
The requirement look simple but not the code :-(
Basically i need to make a report on cumulative sales by product by week.
I have a table with the calendar (including all the weeks) and a view which gives me all the cumulative values by product and sorted by week. What i need the query to do is to give me all the weeks for each products and then add in a column the cumulative values from the view. if this value does not exist, then it should give me the last know record.
Can you help?
Thanks,
The principal is establish all the weeks that a product could have had sales , sum grouping by week, add the missing weeks and use the sum over window function to get a cumulative sum
DROP TABLE IF EXISTS T;
CREATE TABLE T
(PROD INT, DT DATE, AMOUNT INT);
INSERT INTO T VALUES
(1,'2022-01-01', 10),(1,'2022-01-01', 10),(1,'2022-01-20', 10),
(2,'2022-01-10', 10);
WITH CTE AS
(SELECT MIN(YEARWEEK(DT)) MINYW, MAX(YEARWEEK(DT)) MAXYW FROM T),
CTE1 AS
(SELECT DISTINCT YEARWEEK(DTE) YW ,PROD
FROM DATES
JOIN CTE ON YEARWEEK(DTE) BETWEEN MINYW AND MAXYW
CROSS JOIN (SELECT DISTINCT PROD FROM T) C
)
SELECT CTE1.YW,CTE1.PROD
,SUMAMT,
SUM(SUMAMT) OVER(PARTITION BY CTE1.PROD ORDER BY CTE1.YW) CUMSUM
FROM CTE1
LEFT JOIN
(SELECT YEARWEEK(DT) YW,PROD ,SUM(AMOUNT) SUMAMT
FROM T
GROUP BY YEARWEEK(DT),PROD
) S ON S.PROD = CTE1.PROD AND S.YW = CTE1.YW
ORDER BY CTE1.PROD,CTE1.YW
;
+--------+------+--------+--------+
| YW | PROD | SUMAMT | CUMSUM |
+--------+------+--------+--------+
| 202152 | 1 | 20 | 20 |
| 202201 | 1 | NULL | 20 |
| 202202 | 1 | NULL | 20 |
| 202203 | 1 | 10 | 30 |
| 202152 | 2 | NULL | NULL |
| 202201 | 2 | NULL | NULL |
| 202202 | 2 | 10 | 10 |
| 202203 | 2 | NULL | 10 |
+--------+------+--------+--------+
8 rows in set (0.021 sec)
Your calendar date may be slightly different to mine but you should get the general idea.

How to select till the sum reach some value

having this table
#table stock
+-------+----------+
| id | stock |
+-------+----------+
| 1 | 20 |
+-------+----------+
| 2 | 25 |
+-------+----------+
| 3 | 10 |
+-------+----------+
| 4 | 20 |
+-------+----------+
#note: this is an arbitrary random data
How can I keep selecting rows from the table till the sum() of the stock column reaches some value or a little higher , and the table is ORDER BY id ASC.
For example I want to select rows from the table till I have sum of stock '50' , so the result will be
#result 3 rows
+-------+----------+
| id | stock |
+-------+----------+
| 1 | 20 |
+-------+----------+
| 2 | 25 |
+-------+----------+
| 3 | 10 |
+-------+----------+
the sum of stock now is '55' which is the closest possible higher value than '50' , and if we take the next row id:4 the sum of stock will be higher than 50 , and if we remove the row id:3 the value will be 45 which is less than the stock I want 50 .
I can achieve this with PHP by selecting all the rows and loop throw them, but I guess that will be a waste. Is there a possible way to do that on a lower level and let mysql do that for me by a sql query?
Thank you and forgive me if I messed something , I'm new to programming
You need a cumulative sum for this to work. One method uses variables:
select t.*
from (select t.*, (#sum := #sum + stock) as cume_stock
from t cross join
(select #sum := 0) params
order by id
) t
where cume_stock < 50 or (cume_stock >= 50 and cume_stock - stock < 50);

How can i sum every N rows on maria db SQL?

i'm having trouble of finding a way to perform simple addition on a table of maria db, SQL.
i'm having a table called Traffic:
| start_time | end_time | col1 | col2 |
| 1485075600.000000 | 1485075900.000000 | 10 | 20 |
| 1485075900.000000 | 1485076200.000000 | 20 | 30 |
| 1485076200.000000 | 1485076500.000000 | 40 | 50 |
| 1485076500.000000 | 1485076800.000000 | 50 | 60 |
How can i sum every N columns (over col1, and col2) ?
i mean, to merge rows and sum the values of col1, and col2.
assuming the given table, And N = 2,
the result will be:
| start_time | end_time | col1 | col2|
| 1485075600.000000 | 1485076200.000000 | 30 | 50 |
| 1485076200.000000 | 1485076800.000000 | 90 | 110 |
if the table size isn't a multiple of of N, take all you can.
Any one have any idea? i don't have id's to group by on.
You would do this by enumerating the rows. To be correct, you need a column to specify the ordering -- SQL tables represent unordered sets, so they need a column for the ordering.
Let me assume it is start_time. The rest is just aggregation and arithmetic:
select min(start_time) as start_time, max(end_time) as end_time,
sum(col1) as col1, sum(col2) as col2
from (select t.*, (#rn := #rn + 1) as rn
from traffic t cross join
(select #rn := 0) params
order by start_time
) t
group by floor( (rn - 1) / #N);
The #N value is the size of the groups.

Get previous row's value on a MySQL view

Assuming I have something like this :
MySQL table
Date | Val
2013/11/22 | 2
2013/11/23 | 4
2013/11/25 | 12
2013/11/30 | 28
2013/12/02 | 2
I need a query to get on an other column the sum of the "current" row's value plus the previous row's value.
With the example, the result would be something like this :
Date | Value | Total
2013/11/22 | 2 | 2
2013/11/23 | 4 | 6 <--- Because 4+2 = 6
2013/11/25 | 12 | 16
2013/11/30 | 28 | 40
2013/12/02 | 2 | 30
The problem is that I can't use variables because I'm on a view.
How can I do this ?
Any help is appreciated.
SELECT
t.Date,
t.Val,
COALESCE((SELECT Val FROM Table1 sq WHERE sq.Date < t.Date ORDER BY sq.Date DESC LIMIT 1), 0) + t.Val AS whatever
FROM
Table1 t
ORDER BY t.Date
see it working live in an sqlfiddle

MySql sort ascendingly conditionally

Trying to sort rows from lowest to highest continually, or rather repeatedly using MySql. For example: if a column has the following values: 1,3,2,4,2,1,4,3,5, then it should end up like this 1,2,3,4,5,1,2,3,4. So it goes from lowest to highest, but tries to sort again from lowest to highest multiple times.
For large sets, the semi-JOIN operation (the approach in the answer from Strawberry) may create an unwieldy resultset. (Then again, MySQL may have some optimizations in there.)
Another alternative available in MySQL is to use "user variables", like this:
SELECT r.mycol
FROM ( SELECT IF(q.mycol=#prev,#seq := #seq + 1,#seq := 1) AS seq
, #prev := q.mycol AS mycol
FROM mytable q
JOIN (SELECT #prev := NULL, #seq := NULL) p
ORDER BY q.mycol
) r
ORDER BY r.seq, r.mycol
Let me unpack that a bit, and explain what it's doing, starting with the inner query (inline view aliased as r.) We're telling MySQL to get the column (mycol) containing the values you want to sort, e.g. 1,3,2,4,2,1,4,3,5 and we're telling MySQL to order these in ascending sequence: 1,1,2,2,3,3,4,4,5.
The "trick" now is to use a MySQL user variable, so that we can compare the mycol value from the current row to the mycol value from the previous row, and we use that to assign an ascending sequence value, from 1..n on each distinct value.
With that resultset, we can tell MySQL to order by that assigned sequence value first, and then by the value from mycol.
If there is a unique id on each row, then a correlated subquery can be used to get an equivalent result (although this approach is very unlikely to perform as well on large sets)
SELECT r.mycol
FROM mytable r
ORDER
BY ( SELECT COUNT(1)
FROM mytable q
WHERE q.mycol = r.mycol
AND q.id <= r.id
)
, r.mycol
Here's the setup for the test case:
CREATE TABLE mytable (id INT, mycol INT);
INSERT INTO mytable (id, mycol) VALUES
(1,1),(2,3),(3,2),(4,4),(5,2),(6,1),(7,4),(8,3),(9,5);
there is no order two time just this
ORDER BY column ASC
Let's pretend that the PK is a unique integer. Consider the following...
CREATE TABLE seq(id INT NOT NULL PRIMARY KEY,val INT);
INSERT INTO seq VALUES (8,1),(4,2),(1,3),(2,4),(7,0),(6,1),(3,2),(5,5);
SELECT * FROM seq ORDER BY val;
+----+------+
| id | val |
+----+------+
| 7 | 0 |
| 6 | 1 |
| 8 | 1 |
| 3 | 2 |
| 4 | 2 |
| 1 | 3 |
| 2 | 4 |
| 5 | 5 |
+----+------+
SELECT x.*
, COUNT(*) rank
FROM seq x
JOIN seq y
ON y.val = x.val
AND y.id <= x.id
GROUP
BY id
ORDER
BY rank
, val;
+----+------+------+
| id | val | rank |
+----+------+------+
| 7 | 0 | 1 |
| 6 | 1 | 1 |
| 3 | 2 | 1 |
| 1 | 3 | 1 |
| 2 | 4 | 1 |
| 5 | 5 | 1 |
| 8 | 1 | 2 |
| 4 | 2 | 2 |
+----+------+------+