MySQL select using datetime, group by date only - sql

Is is possible to select a datetime field from a MySQL table and group by the date only?
I'm trying to output a list of events that happen at multiple times, grouped by the date it happened on.
My table/data looks like this: (the timestamp is a datetime field)
1. 2010-03-21 18:00:00 Event1
2. 2010-03-21 18:30:00 Event2
3. 2010-03-30 13:00:00 Event3
4. 2010-03-30 14:00:00 Event4
I want to output something like this:
March 21st
1800 - Event 1
1830 - Event 2
March 30th
1300 - Event 3
1400 - Event 4
Thanks!

select date_format(created_at, "%Y-m-%d") as date from tablename GROUP BY date
OR
SELECT DATE_FORMAT(date_column, '%H%i') as time, event FROM table ORDER BY DATE_FORMAT(date_column, '%Y-%m-%d'), time

SELECT DATE_FORMAT(date_column, '%H%i'), DATE_FORMAT(date_column, '%M %D'), event FROM table ORDER BY date_column
%H%i - 1830
%M%D - March 21st

Related

Combine rows by consecutive timestamp

I have an input table as below:
name
time
price
one
2022-11-22 19:00:00 UTC
12
one
2022-11-23 7:00:00 UTC
24
one
2022-11-23 19:00:00 UTC
10
one
2022-11-24 7:00:00 UTC
20
My expected output is:
name
time
price
one
2022-11-22
36
one
2022-11-23
30
Explanation:
I have to group-by 2 consecutive timestamps, the prev date 19:00:00 UTC and the next date 7:00:00 UTC and name the row with the prev date.
Sum the price for each 2 consecutive rows.
Approach:
As I understand, I have to use partition by on the time column, but I cannot figure out how to combine with exact timestamps.
with cte as (
select name,
time,
price,
(row_number() over (partition by name order by time)+1) div 2 as group_no
from consec_data)
select name,
min(time) as time,
sum(price) as price
from cte
group by name, group_no;

Grouping shift data by 7-day windows in SQL Server 2012

What I want to do is to calculate the number of shifts and hours worked by each employee in any given 7-day period. In order to achieve this, I need to identify and group 'islands' of shifts. Note that this 7-day period is not tied to a calendar week and the beginning and ending of this 7-day period would vary from employee to employee. This is sets it apart from other similar questions asked her in the past.
I have a table like this:
Person ID Start Date End Date Start time End time Hours Worked
12345 06-07-20 06-07-20 6:00 AM 7:45 AM 1.75
12345 06-07-20 06-07-20 8:15 AM 8:45 AM 0.50
12345 06-07-20 06-07-20 9:19 AM 9:43 AM 0.40
12345 08-07-20 08-07-20 12:00 AM 12:39 AM 0.65
12345 09-07-20 09-07-20 10:05 PM 11:59 PM 1.90
12345 11-07-20 11-07-20 4:39 PM 4:54 PM 0.25
12345 22-07-20 22-07-20 7:00 AM 7:30 AM 0.50
12345 23-07-20 23-07-20 1:00 PM 3:00 PM 2.00
12345 24-07-20 24-07-20 9:14 AM 9:35 AM 0.35
12345 27-07-20 27-07-20 4:00 PM 6:00 PM 2.00
12345 27-07-20 27-07-20 2:00 PM 4:00 PM 2.00
12345 28-07-20 28-07-20 9:00 AM 10:00 AM 1.00
12345 28-07-20 28-07-20 4:39 AM 4:59 AM 0.34
I want group and summarise the data above like this:
Person ID From To Number of shifts Number of Hours
12345 06-07-20 11-07-20 6 5.45
12345 22-07-20 28-07-20 7 8.19
Note that the first grouping for employee 12345 starts on 06-07-20 and ends on 11-07-20 because these shifts fall within the 06-07-20 - 13-07-20 7-day window.
The next day 7-day window is from 22-07-20 to 28-07-20, which means that the start date for the 7-day window has to be dynamic and based on the data i.e. not constant which makes this a complex task.
Also note that an employee may work multiple shifts in a day and that the shifts may not be consecutive.
I was playing around with using DATEDIFF() with LAG() and LEAD() but was unable to get to where I want. Any help would be appreciated.
I think you need a recursive CTE gor this. The idea is to enumerate the shifts of each person, and then iteratively walk the dataset, while keeping track of the first date of the period - when there is more than 7 days between the start of a period and the current date, the start date resets, and a new group starts.
with recursive
data as (select t.*, row_number() over(partition by personid order by start_date) rn from mytable t)
cte as (
select personid, start_date, start_date end_date, hours_worked, rn
from data
where rn = 1
union all
select
c.personid,
case when d.start_date > dateadd(day, 7, c.start_date) then d.start_date else c.start_date end,
d.start_date,
d.hours_worked,
d.rn
from cte c
inner join data d on d.personid = c.personid and d.rn = c.rn + 1
)
select personid, start_date, max(start_date) end_date, count(*) no_shifts, sum(hours_worked)
from cte
group by personid, start_date
This assumes that:
dates do not span over multiple days, as shown in your sample data
dates are stored as date datatype, and times as time

How can I extract the values of the last aggregation date in sql

I have the following table.
id user time_stamp
1 Mike 2020-02-13 00:00:00 UTC
2 John 2020-02-13 00:00:00 UTC
3 Levy 2020-02-12 00:00:00 UTC
4 Sam 2020-02-12 00:00:00 UTC
5 Frodo 2020-02-11 00:00:00 UTC
Let's say 2020-02-13 00:00:00 UTC is the last day and I would like to query this table to only display last days results? I want to create a view in Bigquery so that I only and always get the last day's results?
So that in the end I get something like this (For last day which is 2020-02-13 00:00:00 UTC )
id user time_stamp
1 Mike 2020-02-13 00:00:00 UTC
2 John 2020-02-13 00:00:00 UTC
You can use window functions:
select t.* except (seqnum)
from (select t.*,
dense_rank() over (order by time_stamp) as seqnum
from t
) t
where seqnum = 1;
This may not work well on a large amount of data -- because of the way that BQ implements window functions with no partitioning. So, you might find that this works better (especially if the above runs out of resources):
select t.*
from t join
(select max(time_stamp) as max_time_stamp
from t
) tt
on t.time_stamp = max_time_stamp;
Also, if the timestamps actually have date components, then you will want to convert to a date or remove the time component somehow.

How to get users which were online everyday last week?

Data example:
id visiting_time
1 13.01.2001 02:34
1 14.01.2001 02:36
1 15.01.2001 02:36
1 16.01.2001 02:37
1 17.01.2001 02:38
1 18.01.2001 02:39
1 19.01.2001 02:40
2 13.01.2001 02:35
2 15.01.2001 02:36
2 16.01.2001 02:37
2 17.01.2001 02:38
2 18.01.2001 02:39
2 19.01.2001 02:40
I want to get all users which were online everyday for the last week, f.e. from 13th january 00:00 till 20th january 00:00.
For my data sample the answer is:
id
1
Considered
everyday for the last week, f.e. from 13th january 00:00 till 20th
january 00:00
and
I point it out myself. In general, I can choose any number of days I
want.
I guess it works only as a filter so the task is "find users online everyday during selected interval
SELECT id,
count(DISTINCT toDate(visiting_time)) AS number_of_days_visited
FROM user_visits
WHERE visiting_time BETWEEN '2001-01-13 00:00:00' AND '2001-01-20 00:00:00'
GROUP BY id
HAVING number_of_days_visited =
round((toUInt32(toDateTime('2001-01-20 00:00:00')) - toUInt32(toDateTime('2001-01-13 00:00:00'))) / 60 / 60 / 24)
In HAVING I computed number of days from the WHERE filter.
The below code will work only if the visiting_time column format is YYYY-MM-DD HH:MM, otherwise the dates are not comparable:
SELECT t.id FROM (SELECT id, COUNT(DISTINCT substr(visiting_time, 1, 10)) AS counter From table1 WHERE ((visiting_time >= '2001-01-13 00:00' AND visiting_time < '2001-01-20 00:00')) GROUP BY id) AS t WHERE t.counter=7

I need to calculate the time between dates in different lines. (PLSQL)

I have a table where I store all status changes and the time that it has been made. So, when I search the order number on the table of times I get all the dates of my changes, but what I realy want is the time (hours/minutes) that the order was in each status.
The table of time seems like this
ID_ORDER | Status | Date
1 Waiting 27/09/2017 12:00:00
1 Late 27/09/2017 14:00:00
1 In progress 28/09/2017 08:00:00
1 Validating 30/09/2017 14:00:00
1 Completed 30/09/2017 14:00:00
Thanks!
Use lead():
select t.*,
(lead(date) over (partition by id_order order by date) - date) as time_in_order
from t;