Calculate interval in timestamps by groups - mysql

I have this table with My Id, "rank" the order messages where sent, and the message_send_time.
ID Rank message_send_time
1 1 2022-01-01 00:33:04
1 2 2022-01-01 00:34:04
2 1 2022-01-01 00:30:04
2 2 2022-01-01 00:32:04
2 3 2022-01-01 00:33:04
I want to calculate the interval of minutes between my group Id and based on the rank oh the messages, how I can calculate this in SQL ?
ID Rank message_send_time Interval_time_minutes
1 1 2022-01-01 00:33:04
1 2 2022-01-01 00:34:04 1
2 1 2022-01-01 00:30:04
2 2 2022-01-01 00:32:04 2
2 3 2022-01-01 00:33:04 1

You can try to use lag window function with TIMESTAMPDIFF
Query #1
select
id,
`Rank`,
message_send_time,
TIMESTAMPDIFF(MINUTE,lag(message_send_time,1) over (partition by id order by `Rank`),message_send_time) Interval_time_minutes
from T;
id
Rank
message_send_time
Interval_time_minutes
1
1
2022-01-01 00:33:04
1
2
2022-01-01 00:34:04
1
2
1
2022-01-01 00:30:04
2
2
2022-01-01 00:32:04
2
2
3
2022-01-01 00:33:04
1
View on DB Fiddle

We can use the functions datediff() and lag()
create table messages(
ID int,
message_send_time timestamp);
insert into messages values
(1,' 2022-01-01 00:33:04'),
(1,' 2022-01-01 00:34:04'),
(2,' 2022-01-01 00:30:04'),
(2,' 2022-01-01 00:32:04'),
(2,' 2022-01-01 00:33:04');
select
id,
rank() over(partition by id order by message_send_time) "Rank",
message_send_time,
timediff(
message_send_time,
lag(message_send_time,1) over (partition by id order by message_send_time)
) as "Interval"
from messages;
id | Rank | message_send_time | Interval
-: | ---: | :------------------ | :-------
1 | 1 | 2022-01-01 00:33:04 | null
1 | 2 | 2022-01-01 00:34:04 | 00:01:00
2 | 1 | 2022-01-01 00:30:04 | null
2 | 2 | 2022-01-01 00:32:04 | 00:02:00
2 | 3 | 2022-01-01 00:33:04 | 00:01:00
db<>fiddle here

select
id
, `Rank`
, message_send_time,
TIMESTAMPDIFF(
MINUTE
, LAG(message_send_time,1) over (
partition by id order by `Rank`
)
, message_send_time
) Interval_time_minutes
from T;

Related

Mysql join on date range

I have a calendar table that looks like this:ยจ
calendar_date
2022-01-01
2022-01-02
2022-01-03
2022-01-04
And another table that has a date_from, and a date to field. If date_to is empty, that row is valid until a more recent date appears.
date_from
date_to
value
2022-01-01
null
1
2022-01-04
2022-01-05
2
2022-01-07
null
3
My expected result is the following:
calendar_date
value
2022-01-01
1
2022-01-02
1
2022-01-03
1
2022-01-04
2
2022-01-05
2
2022-01-06
1
2022-01-07
3
I've tried joining the tables on date_between but it leaves a gap between when 2 ends and 3 begins... This is my query so far:
select
c.calendar_date, v.value
from calendar c
left join values v
on v.start_date <= c.calendar_date
and (
c.calendar_date between v.start_date
and ifnull(
v.stop_date,
ifnull(
(
select min(v2.start_date)
from values v2
where v2.start_date > v.start_date
),
date_add(curdate(), interval 2 year)
)
)
)
Like this:
calendar_date
value
2022-01-01
1
2022-01-02
1
2022-01-03
1
2022-01-04
2
2022-01-05
2
2022-01-06
null
2022-01-07
3

Find rows where ID matches and date is within X days

Somewhat new to SQL and I'm running into a bit of issue with a project. I have a table like this:
ID
subscription_ID
renewal_date
1
11
2022-01-01 00:00:00
2
11
2022-01-02 00:00:00
3
12
2022-01-01 00:00:00
4
12
2022-01-01 12:00:00
5
13
2022-01-01 12:00:00
6
13
2022-01-03 12:00:00
My goal is to return rows where the subscription_ID matches and the start_date is within or equal to a certain # of days (hours would work as well). For instance, I'd like rows where subscription_ID matches and the start_date is within or equal to 1 day such that my results from the table above would be:
ID
subscription_ID
renewal_date
1
11
2022-01-01 00:00:00
2
11
2022-01-02 00:00:00
3
12
2022-01-01 00:00:00
4
12
2022-01-01 12:00:00
Any assistance would be greatly appreciated--thanks!
If I understand correctly maybe you are trying something like:
select t.*
from test_tbl t
join ( SELECT subscription_id
, MAX(diff) max_diff
FROM
( SELECT x.subscription_id
, DATEDIFF(MIN(y.start_date),x.start_date) diff
FROM test_tbl x
JOIN test_tbl y ON y.subscription_id = x.subscription_id
AND y.start_date > x.start_date
GROUP BY x.subscription_id , x.start_date
) z
GROUP BY subscription_id
) as t1 on t.subscription_id=t1.subscription_id
where t1.max_diff<=1;
Result:
id subscription_id start_date
1 11 2022-01-01 00:00:00
2 11 2022-01-02 00:00:00
3 12 2022-01-01 00:00:00
4 12 2022-01-01 12:00:00
The subquery returns:
subscription_id max_diff
11 1
12 0
13 2
which is used on the where condition.
Demo

Cumulative count for each ID

Data:
Create table completion(user integer, count integer, completed date);
Insert into completion values (100,1,'2021-01-01'),(100,4,'2021-01-02'),(100,2,'2021-01-03'),
(101,4,'2021-01-05'),(101,5,'2021-01-08'),(102,1,'2021-01-04');
I want to produce 2 tables.
The 1st target is to get a cumulative count with respect to date for each individual ID:
user| cumulative | date
100| 1 | 2021-01-01
100| 5 | 2021-01-02
100| 7 | 2021-01-03
101| 4 | 2021-01-05
101| 9 | 2021-01-08
102| 1 | 2021-01-04
The 2nd target is to transform the date into number of days, counted from the minimum date for that ID:
user| cumulative | days passed
100| 1 | 0
100| 5 | 1
100| 7 | 2
101| 4 | 0
101| 9 | 3
102| 1 | 0
Thanks.
You can use window functions:
select c.*,
sum(count) over (partition by user order by completed) as cumulative,
datediff(completed, min(completed) over (partition by user)) as days_passed
from completion c;
Here is a db<>fiddle.

mySQL how to select some data in the same field from limit date

I got the data from my table with the query
SELECT dt, place
FROM horseri
WHERE horseid = 'C299'
AND dt < '20200715'
ORDER BY dt DESC
as below, where dt is the date and the place is the winning place
dt | place
----------------------
2020-07-12 | 8
2020-06-07 | 2
2020-05-17 | 3
2020-04-12 | 9
2020-03-29 | 12
2020-03-01 | 3
2020-02-16 | 4
2020-01-27 | 5
2019-12-18 | 3
2019-11-23 | 10
2019-10-30 | 2
2019-10-01 | 9
2019-09-08 | 2
2019-07-14 | 7
2019-07-01 | 13
2019-06-16 | 7
2019-05-18 | 8
2019-03-31 | 13
2019-03-17 | 12
How can I get the first 3 winning places from the data only by the last 10 date ?
My expected output will be
dt | place
----------------------
2020-06-07 | 2
2020-05-17 | 3
2020-03-01 | 3
2019-12-18 | 3
Use a subquery to get the most recent 10 dates. Then select the top 3 places from that.
SELECT dt, place
FROM (
SELECT dt, place
FROM horseri
where horseid = 'C299'
ORDER BY dt DESC
LIMIT 10
) as x
WHERE place <= 3
The more modern way of writing Barmar's answer (assuming it be what the OP wants here), would be to use ROW_NUMBER:
SELECT dt, place
FROM
(
SELECT *, ROW_NUMBER() OVER (ORDER BY dt DESC) rn
FROM horseri
WHERE horseid = 'C299'
) t
WHERE rn <= 10 AND place <= 3;
To isolate individual places, just change the outer WHERE clause. For example, for second place finishers in the most recent 10 dates, use:
WHERE rn <= 10 AND place = 2

Get report of last week of all days including days with 0 count

I am trying to get a report of last week entries/tickets and show 0 if that day there was none entries and then show it in google line chart for a project.MySQL table look like this
----------------------------------
id body timeSent
----------------------------------
1 someText 2020-02-29 15:48:18
2 someText 2020-03-02 11:32:07
3 someText 2020-03-02 11:32:07
4 someText 2020-03-04 12:11:13
5 someText 2020-03-05 09:32:09
----------------------------------
I wrote query like this
SELECT count(*) as count_tickets,
substr(timeSent,1,10) AS datetime
FROM tableName
WHERE substr(timeSent,1,10) >= DATE(NOW()) - INTERVAL 7 DAY
GROUP BY substr(timeSent,1,10)
ORDER BY timeSent
Output look like this
----------------------------------
count_tickets dateTime
----------------------------------
1 2020-02-29
2 2020-03-02
1 2020-03-04
1 2020-03-05
----------------------------------
What my required output is
----------------------------------
count_tickets dateTime
----------------------------------
1 2020-02-29
0 2020-03-01
2 2020-03-02
0 2020-03-03
1 2020-03-04
1 2020-03-05
0 2020-03-06
----------------------------------
How can I achieve this?
For just 7 days, one method is to use a derived table of numbers, and left join it with the original table:
select
count(t.timesent) as count_tickets,
current_date - interval x.n day as datetime
from (
select 0 n union all select 1 union all select 2 union all select 3
union all select 4 union all select 5 union all select 6
) x
left join tablename t
on t.timesent >= current_date - interval x.n day
and t.timesent < current_date - interval (x.n - 1) day
group by x.n
order by x.n desc
Demo on DB Fiddle:
count_tickets | datetime
------------: | :---------
1 | 2020-02-29
0 | 2020-03-01
2 | 2020-03-02
0 | 2020-03-03
1 | 2020-03-04
1 | 2020-03-05
0 | 2020-03-06