How to find cumulative sum between two dates in MySQL? - mysql

How to find cumulative sum between two dates taking into account the previous state?
Putting WHERE condition
WHERE date BETWEEN '2021-02-19 12:00:00'AND '2021-02-21 12:00:00';
doesn't do the job because the sum starts from the first condition's date, and not from the first record. I would like to select only part of the whole query (between two dates), but to calculate cumulative sum from the first (initial) state.
I prepared Fiddle
CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`date` datetime NOT NULL DEFAULT current_timestamp(),
`payment` double NOT NULL
);
INSERT INTO `table1` (`id`, `date`, `payment`) VALUES
(1, '2021-02-16 12:00:00', 100),
(2, '2021-02-17 12:00:00', 200),
(3, '2021-02-18 12:00:00', 300),
(4, '2021-02-19 12:00:00', 400),
(5, '2021-02-20 12:00:00', 500),
(6, '2021-02-21 12:00:00', 600),
(7, '2021-02-22 12:00:00', 700);
version();
SELECT DATE_FORMAT(date, "%Y-%m-%d") AS date,
payment, SUM(payment) OVER(ORDER BY id) AS balance
FROM table1
WHERE date BETWEEN '2021-02-19 12:00:00'AND '2021-02-21 12:00:00';

You must filter the table after you get the cumulative sums:
SELECT *
FROM (
SELECT DATE(date) AS date,
payment,
SUM(payment) OVER(ORDER BY id) AS balance
FROM table1
) t
WHERE date BETWEEN '2021-02-19'AND '2021-02-21';
or:
SELECT *
FROM (
SELECT DATE(date) AS date,
payment,
SUM(payment) OVER(ORDER BY id) AS balance
FROM table1
WHERE DATE(date) <= '2021-02-21'
) t
WHERE date >= '2021-02-19';
See the demo.
Results:
date
payment
balance
2021-02-19
400
1000
2021-02-20
500
1500
2021-02-21
600
2100

Related

Write a query to identify frequent posters

I'm trying to write a query that will find the user_id's of all users
that have created a minimum of two posts in a maximum of 1 hour.
Here's a light example of the data:
CREATE TABLE tbl_posts
(`id` int, `user_id` int, `created_date` datetime);
INSERT INTO tbl_posts
(`id`, `user_id`, `created_date`)
VALUES
(1, 1, '2021-07-01 09:00'),
(2, 2, '2021-07-01 10:15'), -- *
(3, 2, '2021-07-01 11:00'), -- * user posted twice within an hour.
(4, 3, '2021-07-01 13:00'),
(5, 3, '2021-07-01 15:00'),
(6, 3, '2021-07-01 18:00'),
(7, 4, '2021-07-01 11:00'),
(8, 4, '2021-07-02 11:30'),
(9, 4, '2021-07-03 12:30'), -- *
(10, 4, '2021-07-03 12:45'); -- * user posted twice within an hour.
http://sqlfiddle.com/#!9/0e7cba
The expected output of the query is
2, 4
This output is expected because users 2 and 4 have each posted at least twice in under an hour.
I don't know where to begin with this in MySQL. I can export the data and get a result procedurally in something like C or Python, but I'm sure this is accomplishable in MySQL and am curious to know how. Maybe I need a Window function?
Use EXISTS:
SELECT DISTINCT t1.user_id
FROM tbl_posts t1
WHERE EXISTS (
SELECT 1
FROM tbl_posts t2
WHERE t2.user_id = t1.user_id
AND t1.created_date < t2.created_date
AND TIMESTAMPDIFF(SECOND, t1.created_date, t2.created_date) <= 60 * 60
)
Or, if your version of MySql is 8.0+ use LEAD() window function:
SELECT user_id
FROM (
SELECT *, TIMESTAMPDIFF(
SECOND,
created_date,
LEAD(created_date) OVER (PARTITION BY user_id ORDER BY created_date)
) diff
FROM tbl_posts
) t
GROUP BY user_id
HAVING MIN(diff) <= 60 * 60
See the demo.
select distinct p.user_id from tbl_posts p
inner join tbl_posts p2 on p.user_id = p2.user_id
and p.created_date < p2.created_date
and DATE_ADD(p.created_date,interval 1 hour) >= p2.created_date

Find avg, min, and max of grouped by rows

I have created the following schema:
CREATE TABLE test (
id INT,
stat_id INT,
time DATETIME
);
INSERT INTO test (id, stat_id, time) VALUES (1, 1, '2020-09-21 00:02:31');
INSERT INTO test (id, stat_id, time) VALUES (5, 1, '2020-09-21 00:06:31');
INSERT INTO test (id, stat_id, time) VALUES (2, 2, '2020-09-19 00:08:31');
INSERT INTO test (id, stat_id, time) VALUES (3, 2, '2020-09-21 00:03:31');
INSERT INTO test (id, stat_id, time) VALUES (6, 2, '2020-09-23 00:02:31');
INSERT INTO test (id, stat_id, time) VALUES (4, 2, '2020-09-27 00:04:31');
INSERT INTO test (id, stat_id, time) VALUES (7, 3, '2020-09-20 00:04:31');
INSERT INTO test (id, stat_id, time) VALUES (8, 3, '2020-09-23 00:05:31');
https://www.db-fiddle.com/f/6CRv6XqYMAfkBHEBhz1zGe/1
I have 3 different stat_id groups.
They are ordered by the id (smallest to largest).
I need to find the avg duration between one event in each group to the the next.
For example, for site_id = 2, I need to get the difference between the 2020-09-21 and 2020-09-19, then 2020-09-23 and 2020-09-21, and then 2020-09-27 and 2020-09-23.
And then I need to get the avg duration between each of those rows, the maximum time (which be the time between the 2020-09-27 and 2020-09-23) and the minimum time.
I need to do this for all 3 stat_id groups.
I'm essentially looking, on average, how long it took for each each stat_id group to create a new row.
I tried something like:
select
stat_id,
AVG(time) as avg,
timestampdiff(hour, min(time), max(time)) as diff_in_hours,
from test
group by stat_id;
but obviously this is wrong. It gives the wrong average and just gives the difference between the biggest and the smallest in each group, which is not exactly what I am looking for. I am not sure how to do the difference between one row and its previous row?
One option uses lag():
select stat_id, avg(diff) avg_diff
from (
select t.*,
timestampdiff(hour, lag(time) over(partition by stat_id order by id), time) diff
from test t
) t
group by stat_id

MySQL get earliest record of each day

The query below gives me one record per day for each user. How can I modify it so that it gives me the earliest record per day for each user?
I tried using MIN() on the date field in the GROUP BY part, but that obviously doesn't work. There's a date_trunc function mentioned in this answer which seems to do what I want, but it is not available in MySQL. What's the best way to go about this?
For the sample data below, the query should return records with ids 1, 3, 5, and 7.
SELECT user_id, coords, date
FROM table
WHERE draft = 0
GROUP BY user_id, DAY('date')
CREATE TABLE `table` (
`id` bigint(20) UNSIGNED NOT NULL,
`user_id` int(11) NOT NULL,
`coords` point NOT NULL,
`date` datetime NOT NULL,
`draft` tinyint(4) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `table` (`id`, `user_id`, `coords`, `date`, `draft`) VALUES
(1, 1, xxx, '2020-11-08 18:01:47', 0),
(2, 1, xxx, '2020-11-08 18:05:47', 0),
(3, 1, xxx, '2020-11-09 18:06:47', 0),
(4, 1, xxx, '2020-11-09 18:07:47', 0),
(5, 2, xxx, '2020-11-08 17:01:47', 0),
(6, 2, xxx, '2020-11-08 17:05:47', 0),
(7, 2, xxx, '2020-11-09 14:00:47', 0),
(8, 2, xxx, '2020-11-09 14:05:47', 0),
A typical approach is to filter with a correlated subquery:
select t.*
from mytable t
where t.draft = 0 and t.date = (
select min(t1.date)
from mytable t1
where t1.draft = t.draft and t1.user_id = t.user_id and date(t1.date) = date(t.date)
)
You can optimize the subquery a little by using a half-open interval for filtering:
select t.*
from mytable t
where t.draft = 0 and t.date = (
select min(t1.date)
from mytable t1
where
t1.user_id = t.user_id
and t1.draft = t.draft
and t1.date >= date(t.date)
and t1.date < date(t.date) + interval 1 day
)
The second query should be able to take advantage of an index on (draft, user_id, date).
Alternatively, if you are running MuSQL 8.0, you can also use window functions:
select *
from (
select t.*, row_number() over(partition by user_id, date(date) order by date) rn
from mytable t
where draft = 0
) t
where rn = 1
Use:
SELECT user_id, coords, date
FROM `table`
WHERE draft = 0
GROUP BY DAY('date'), user_id order by user_id, date

Count results for the current date using fields of type datetime

I am trying to count the entries for the current day and sum the total. Currently, I have a query that counts the entries per day. I am using the datetime field to achieve my end goal. What would be the best approach to count the entries for the current day and sum the total?
CREATE TABLE product_entry
(`id` int, `entry_time` datetime, `product` varchar(55))
;
INSERT INTO product_entry
(`id`, `entry_time`, `product`)
VALUES
(1, '2015-09-03 15:16:52', 'dud1'),
(2, '2015-09-03 15:25:00', 'dud2'),
(3, '2015-09-04 16:00:12', 'dud3'),
(4, '2015-09-04 17:23:29', 'dud4')
;
SQLFIDDLE
Query
SELECT entry_time, count(*)
FROM product_entry
GROUP BY hour( entry_time ) , day( entry_time )
Schema
CREATE TABLE product_entry
(`id` int, `entry_time` datetime, `product` varchar(55))
;
INSERT INTO product_entry
(`id`, `entry_time`, `product`)
VALUES
(1, '2015-09-03 15:16:52', 'dud1'),
(2, '2015-09-03 15:25:00', 'dud2'),
(3, '2015-09-04 16:00:12', 'dud3'),
(4, '2015-09-04 17:23:29', 'dud4')
;
The title of your question says Count results for the current date ..., but the query you have tried suggests you want to show result counts for every distinct date. I am not sure which one you need. If the former is the case, you could simply use:
SELECT COUNT(`id`) FROM `product_entry` WHERE DATE(`entry_time`) = CURDATE()
To get count for today:
SELECT COUNT(`id`) FROM `product_entry` WHERE DATE(`entry_time`) = CURRENT_DATE
To get count for yesterday (needed when You want to get entries at end of the day):
SELECT COUNT(`id`) FROM `product_entry` WHERE DATE(`entry_time`) = SUBDATE(CURRENT_DATE, 1)
For all time grouped by date and formated:
SELECT DATE_FORMAT(entry_time,'%Y-%m-%d'), count(*)
FROM product_entry
GROUP BY date(entry_time)
this is MSSQL Code maybe your help
SELECT day([product_entry].[entry_time])as input, count(*) as Miktar
FROM [product_entry]
GROUP BY day([entry_time])

Unique value per day

i am looking how to have unique value per day, here an exemple:
CREATE TABLE IF NOT EXISTS calls (
id int(11) default NULL,
calldate datetime default NULL,
dst varchar(80) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO calls (id, calldate, dst) VALUES
(1, '2014-05-03 20:45:43', '22561037352'),
(2, '2014-05-04 20:07:49', '22561037352'),
(3, '2014-05-04 13:16:14', '22561037352'),
(4, '2014-05-04 20:08:58', '22560991034'),
(5, '2014-05-04 16:06:02', '22560991034'),
(6, '2014-05-04 20:22:19', '22560842218');
sqlfiddle: Copy and paste to test
we have two number coming two times per day 22561037352 & 22560991034, i want to show unique number per day.
http://sqlfiddle.com/#!9/84076/11
SELECT DISTINCT DATE_FORMAT (calldate,'%Y-%m-%d') calldate, dst
FROM calls
SELECT DISTINCT t.*
FROM (SELECT DATE (calldate) as calldate, dst FROM calls) t
First call to the number for the day
SELECT *
FROM calls c
WHERE NOT EXISTS (SELECT 'a'
FROM calls c2
WHERE c2.dst = c.dst
AND DATE_FORMAT(c2.calldate,'%d/%m/%Y') = DATE_FORMAT(c.calldate,'%d/%m/%Y')
AND c2.calldate < c.calldate
)