We have a records table with the following data. We need to fill fifty-two week(or 365 days)high and low amounts in ft_high and ft_low columns? How can we accomplish this in MySQL?
Fifty-two-week data including the same date.
id user_id date amount ft_high ft_low
10 21 2020-10-11 1500 1800 950
11 22 2020-10-12 1950 2410 1738
12 21 2020-10-15 1150 1800 1500
----------------------------------------
----------------------------------------
99 21 2020-11-15 1950 1950 950
You can use window functions:
selet t.*,
min(amount) over (partition by user_id order by date range between interval 52 week preceding and current row) as ft_low,
max(amount) over (partition by user_id order by date range between interval 52 week preceding and current row) as ft_high,
from t;
Related
Table "users":
id
name
email
created_at
46
FSDSD2
FSDSD2#thebluedot.co
2022-05-29 14:19:21
47
Fxz3
Fxz3#gmail.com
2022-05-30 20:12:15
48
Fgh3
Fgh3#gmail.com
2022-05-31 20:12:15
49
Fghxc3
Fghxc3#gmail.com
2022-06-01 20:12:15
50
Fdx3
Fdx3#gmail.com
2022-06-02 20:12:15
51
Fg3q3
Fg3q3#gmail.com
2022-06-03 20:12:15
88
Fbhgt
Fbhgt#gmail.co
2022-05-23 16:38:41
112
Fht
Fht#gmail.com
2022-05-24 16:19:23
113
Y14gss
Y14gss#gmail.com
2022-05-25 16:42:44
114
sfhf
sfhf#gmail.com
2022-05-26 12:10:40
115
A2czu
A2czu#thebluedot.co
2022-05-27 14:00:31
116
Cc1sn
Cc1sn#gmail.com
2022-05-28 12:04:56
Table "oxygen_point_earns":
id
user_id
oxygen_point
created_at
2
116
50.00
2022-05-23 17:49:30
3
113
10.00
2022-05-24 07:49:46
4
114
10.00
2022-05-25 07:50:42
5
46
50.00
2022-05-26 07:55:19
6
47
40.00
2022-05-27 13:28:17
7
48
30.00
2022-05-28 13:32:19
8
49
10.00
2022-05-29 13:32:19
9
50
5.00
2022-05-30 13:32:19
10
51
10.00
2022-05-31 13:32:19
11
88
20.00
2022-06-01 13:32:19
12
112
50.00
2022-06-02 13:32:19
13
115
10.00
2022-06-03 13:32:19
14
112
20.00
2022-06-03 16:32:19
I have two tables:
"users", which stores users basic information
"oxygen_point_earns", which stores oxygen points earned by specific users
The "users" table has 12 rows, though the "oxygen_point_earns" table contains 13 records, which means that one user can win points even more than once.
I was trying to made some calculation between those tables (e.g. dividing the total of weekly gained points by the weekly users cumulative sum, for each user). The problem occurs when I attempt to get the users cumulative sum.
SELECT STR_TO_DATE(CONCAT(YEARWEEK(op.created_at), ' Sunday'), '%X%V %W') AS week,
SUM(COUNT(*)) OVER(ORDER BY MIN(op.created_at)) AS user_count,
SUM(op.oxygen_point) AS op_weekly
FROM users us
LEFT JOIN oxygen_point_earns op
ON us.id = op.user_id
GROUP BY week
ORDER BY week
This query gets me the following output:
As you can see, even though the points are correctly computed, the total user count is wrong at the second row: it should be 12 instead of 13 (First week I got 6 users then next week 6 more users registered. So my total user count is 12. On second row I should get 12.)
I tried DISTINCT, GROUP_CONCAT but didn't work. How can I fix this query to get true result of users counts?
One straightforward option is to separate the two operations (aggregation and windowing) using a subquery/cte:
WITH cte AS (
SELECT STR_TO_DATE(CONCAT(YEARWEEK(op.created_at), ' Sunday'), '%X%V %W') AS week,
COUNT(DISTINCT user_id) AS cnt,
SUM(op.oxygen_point) AS op_weekly
FROM users us
LEFT JOIN oxygen_point_earns op ON us.id = op.user_id
GROUP BY week
)
SELECT week,
SUM(cnt) OVER(ORDER BY week) AS user_count,
op_weekly
FROM cte
ORDER BY week
I have a table
DAY 1
ID
amount
DATE
1
10
12-02-2020
2
15
12-02-2020
3
20
12-02-2020
4
25
12-02-2020
I did a sum of the amount on day one which turns out to be 70
Now next day I have few more rows where the amount is UPDATED an APPENDED
New tables looks like this
DAY 2
ID
amount
DATE
1
10
12-02-2020
2
20
13-02-2020
3
20
12-02-2020
4
25
12-02-2020
5
30
13-02-2020
6
35
14-02-2020
Now if you see the ID 2 has new updates amount which is 20 earlier 15
and it has new data from dates 13 and 14 on ID 5 and 6
Can I just run a query where it will only process the changed data and add it to the
previous sum
so like 30+35+5(as only 5 increased from the last value)
total = 70
Mainly to process changed data
This will very much depend on how the historical data will be provided.
This example requires additional Day column in the historical data table AND that you're using a MySQL version that supports LAG() (e.g. MySQL v8+ OR MariaDB 10.3+). Let's assume that it's possible for the historical data table to be like this:
ID
Amount
Date
Day
1
10
2020-02-12
1
2
15
2020-02-12
1
3
20
2020-02-12
1
4
25
2020-02-12
1
1
10
2020-02-12
2
2
20
2020-02-13
2
3
20
2020-02-12
2
4
25
2020-02-12
2
5
30
2020-02-13
2
6
35
2020-02-14
2
.. then maybe a query like this:
SELECT Day,
SUM(amount) AS Total,
SUM(amount)-LAG(SUM(amount)) OVER (ORDER BY Day) AS diff
FROM historical_data
GROUP BY Day
ORDER BY Day;
OR (in for MariaDB):
SELECT Day, Total,
Total-LAG(Total) OVER (ORDER BY Day) AS Diff
FROM
(SELECT Day,
SUM(amount) AS Total
FROM historical_data
GROUP BY Day) A;
This will return result like:
Day
Total
diff
1
70
2
140
70
I was following an example from this site on how to use LAG() to get the row data value above it an using them to subtract the SUM(amount) value for that day.
Here's a demo fiddle of the experiment.
I have running total
SELECT
id,
DepositValue,
action_date,
SUM(DepositValue) OVER(ORDER by action_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Running_total
The above select returns me the following:
id action_date DepositValue Running_total
1 2020-04-01 20 20
2 2020-04-02 2 22
3 2020-04-03 8 30
4 2020-04-04 10 38
5 2020-04-05 14 48
6 2020-04-06 15 62
7 2020-04-07 22 77
8 2020-04-08 12 99
9 2020-04-09 4 103
What i want to achieve is selecting only part of Running_total depend on action_date with already calculated values like this.
id action_date DepositValue Running_total
3 2020-04-03 8 30
4 2020-04-04 10 38
5 2020-04-05 14 48
You can turn your query to a subquery and filter in the outer query:
SELECT *
FROM (
SELECT
id,
DepositValue ,
action_date,
SUM(DepositValue) OVER(ORDER by action_date) AS Running_total
FROM mytable
) t
WHERE action_date BETWEEN '2020-04-03' AND '2020-04-05'
Note that window specification ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW is actually the default when not specificed, hence you can just remove it.
Also, your original query was missing a FROM clause, I added it.
I want to get sum of products per day wise for one specific month
SELECT SUM(instock) as 'Opening Stock',SUM(receipt)as 'Receipt',date FROM product WHERE date=(SELECT Date FROM product GROUP BY date)
Input
id instock receipt date
1 100 100 2019-07-01
2 300 100 2019-07-01
3 450 300 2019-07-01
1 200 100 2019-07-02
2 500 200 2019-07-02
3 300 200 2019-07-02
1 100 50 2019-07-03
2 150 50 2019-07-03
3 250 150 2019-07-03
Required Output
Opening Stock Receipt date
850 500 2019-07-01
1000 500 2019-07-02
500 250 2019-07-03
You just need a simple GROUP BY query:
SELECT
SUM(instock) AS `Opening Stock`,
SUM(receipt) AS Receipt,
date
FROM product
GROUP BY
date
ORDER BY
date;
In your current attempt, it appears that you were trying to use a WHERE clause with a subquery to limit the possible date values to only one distinct value per group. But, GROUP BY does this heavy lifting for you.
I have Table with 3 Columns, Column1 with Date and Column2 stores Points which is nothing but Some random Number between 1 to 9 and column 3 which have some unique email address in every cell.
Now I want to add the points grouped by date for last 5 days.
That is if I have 3 rows for day one, 1 rows for day two, 3 rows for day 3 and 2 rows for day 4 & 5 I should get the sum of points of these 11 rows grouped by date as 5 rows for five days.
Input
Date Points
Email
2012-07-01 5 a#sample.com
2012-07-01 6 b#sample.com
2012-07-01 2 c#sample.com
2012-07-02 5 d#sample.com
2012-07-03 8 e#sample.com
2012-07-03 7
f#sample.com
2012-07-03 1
y#sample.com
2012-07-04 3 x#sample.com
2012-07-04 2 f#sample.com
2012-07-05 3 g#sample.com
2012-07-05 9 b#sample.com
Output
Date Points
2012-07-01 13
2012-07-02 5
2012-07-03 16
2012-07-04 5
2012-07-05 12
Please suggest me a MySQL query for the above.
select `Date`,sum(`Points`) from my_table group by `Date`;
select `Date`,sum(`Points`) from my_table group by `Date` Limit 5;
select Date,sum(Points) from my_table group by Date;
select [Date],SUM(Points)
from myTable1
group by [Date]
You can do:
SELECT date, SUM(points) AS points
FROM tbl
WHERE date > CURDATE() - INTERVAL 5 DAY
GROUP BY date