How can I condition the time column? - mysql

There is a column representing 24 hours.
Data comes in every 15 minutes.
For example, at 10:15, the value is entered in the DateTime column of the 10H column.
But... The client wants to set the standard for the day at 6:30 a.m. and set it to 6:30 the next day.
If you look at the column below, should sum the value from column 6h.. Is there any way?
DateTime 0H 1H ..6H....7H...8H..9H..10H..~23H
2020 11 10 00:00:00 979 958
2020 11 10 00:15:00 987 954
2020 11 10 00:30:00 987 958
2020 11 10 00:45:00 960 956
2020 11 11 00:00:00 0 0
2020 11 11 00:15:00 0 0
2020 11 11 00:30:00 0 0
2020 11 11 00:45:00 0 0
2020 11 12 00:00:00 995 995
2020 11 12 00:15:00 991 993
2020 11 12 00:30:00 1000 993
2020 11 12 00:45:00 993 996
I want value
2020-11-15 06:30 ~ 2020-11-16 06:30 values sum

Consider breaking hour blocks into separate SELECT segments that add corresponding hour columns. Then, bind all parts together by UNION ALL. Finally, aggregate all hour blocks for final SUM.
Below sums all values between 2020-11-15 06:30 - 2020-11-16 06:30 (not including upper limit). Be sure to fill in the abbreviated ... for needed columns:
SELECT SUM(sub.HoursTotal) AS DayTotal
FROM
(
-- PARTIAL HOUR - 6:30 AM - 6:45 AM
SELECT [6h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-15 00:30:00' AND
'2020 11-15 00:45:00'
UNION ALL
-- FULL HOURS - 7:00 AM - 23:00 PM
SELECT [7h] + [8h] + ... + [23h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-15 00:00:00' AND
'2020 11-15 00:45:00'
UNION ALL
-- FULL HOURS - 12:00 AM - 5:00 AM
SELECT [0h] + [1h] + ... + [5h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-16 00:00:00' AND
'2020 11-16 00:45:00'
UNION ALL
-- PARTIAL HOUR - 6:00 AM - 6:15 AM
SELECT [6h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-16 00:00:00' AND
'2020 11-16 00:15:00'
) sub
Of course, ideally your table maintains a normalized structure of long format with two columns for datetime and value. Then, querying is much easier:
logDateTimewithHour Value
2020 11-15 00:00:00 ###
2020 11-15 00:15:00 ###
2020 11-15 00:30:00 ###
2020 11-15 00:45:00 ###
2020 11-15 01:00:00 ###
2020 11-15 01:15:00 ###
2020 11-15 01:30:00 ###
2020 11-15 01:45:00 ###
... ...
2020 11-16 22:00:00 ###
2020 11-16 22:15:00 ###
2020 11-16 22:30:00 ###
2020 11-16 22:45:00 ###
2020 11-16 23:00:00 ###
2020 11-16 23:15:00 ###
2020 11-16 23:30:00 ###
2020 11-16 23:45:00 ###
SELECT SUM(Value) AS DayTotal
FROM myLongTable
WHERE logDateTimewithHour BETWEEN '2020 11-15 06:30:00'
AND '2020 11-16 06:15:00'

Related

Creating custom week number in sql

I have a table with ID and Date columns.
Table A:
ID
Date
24
2019-10-29
24
2019-10-30
24
2019-10-31
.....
....
I need to add a column called "Week_Num" such that:
If there is a new "ID" and the first date begins on a Tuesday (eg: 29th Oct,2019 in ID 24 is Tuesday) then the week will start with 1
Week will always end on Saturday irrespective of whether 7 days are over or not with only one exception (see point 3)
If there is a new "ID" and the first date begins before Tuesday (eg: 25th Oct,2020 in ID 25 is Sunday) then the week will start with 0 and once it reaches Tuesday the week_num will become 1.
Expected Output:
ID
Date
Day_Of_Week
Week_Num
24
2019-10-29
Tue
1
24
2019-10-30
Wed
1
24
2019-10-31
Thur
1
24
2019-11-01
Fri
1
24
2019-11-02
Sat
1
24
2019-11-03
Sun
2
24
2019-11-04
Mon
2
24
2019-11-05
Tues
2
24
2019-11-06
Wed
2
24
2019-11-07
Thurs
2
24
2019-11-08
Fri
2
24
2019-11-09
Sat
2
24
..........
.
..
24
2020-03-14
.
..
25
2020-10-25
Sun
0
25
2020-10-26
Mon
0
25
2020-10-27
Tue
1
25
2020-10-28
Wed
1
25
2020-10-29
Thur
1
25
2020-10-30
Fri
1
25
2020-10-31
Sat
1
What I have so far:
select
distinct ID,min(Date) over (partition by ID order by date) as firstTuesdayOfSeason
from
TableA
group by ID,Date
having datepart(weekday,Date)=3
which gets the first Tuesday for every new ID and gives the following output:
ID
firstTuesdayOfSeason
24
2019-10-29
25
2020-10-27
I was thinking of joining this table with the Table A (the one with ID, Date as columns) but I don't know how to implement the weird Saturday logic.
This might work for you.
Find min-date, offset to Tuesday for each ID, and calculate using date-diff for each row against the min-date
select a.ID, a.Date, weekday(a.Date), greatest(0, 1 + floor((datediff(a.Date, b.since) - b.off) / 7)) week_num
from TableA a
join (
select ID, min(Date) As since, (case when weekday(min(Date)) > 1 then 8 - weekday(min(Date)) else 1 - weekday(min(Date)) end) off
from TableA
group by ID
) b ON a.ID = b.ID
order by a.ID, a.Date
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=657c96465338a398ced73bc256ff92c0

MySQL Get data by previous quarter

I am trying to find the last entry for the previous years quarter.
All I can access is year i.e 2021 and quarter i.e 1
Here is the data in my database:
id
name
start
end
16
April 2021
2021-04-01
2021-04-30
15
March 2021
2021-03-01
2021-03-31
14
February 2021
2021-02-01
2021-02-28
57
November 2020
2020-11-01
2020-11-30
55
October 2020
2020-10-01
2020-10-31
29
September 2020
2020-09-01
2020-09-30
27
July 2020
2020-07-01
2020-07-31
24
April 2020
2020-04-01
2020-04-30
23
March 2020
2020-03-01
2020-03-31
22
February 2020
2020-02-01
2020-02-29
21
January 2020
2020-01-01
2020-01-31
Using the MySQL quarter function I can get it to print out the quarter as an integer in another column:
SET #given_year = 2021;
SET #given_quarter = 1;
SELECT
id, name, start, end, QUARTER(end) as "Q"
FROM
submissions
id
name
start
end
Q
16
April 2021
2021-04-01
2021-04-30
2
15
March 2021
2021-03-01
2021-03-31
1
14
February 2021
2021-02-01
2021-02-28
1
57
November 2020
2020-11-01
2020-11-30
4
55
October 2020
2020-10-01
2020-10-31
4
29
September 2020
2020-09-01
2020-09-30
3
27
July 2020
2020-07-01
2020-07-31
3
24
April 2020
2020-04-01
2020-04-30
2
23
March 2020
2020-03-01
2020-03-31
1
22
February 2020
2020-02-01
2020-02-29
1
21
January 2020
2020-01-01
2020-01-31
1
I tried using WHERE and LIKE but it is returning 0 rows:
SELECT * FROM (
SELECT
id, name, start, end, QUARTER(end) as "Q"
FROM
submissions as s
) AS vs
WHERE
vs.end
LIKE
#given_year
AND
vs.Q < #given_quarter
I also need to account for the possibility that there may be no rows this year and I need to find the previous year.
For example with these two rows, if I was passed the year 2021 and quarter 1 I would need to return November of the previous year and a different quarter.
id
name
start
end
Q
14
February
2021
2021-02-01
2021-02-28
57
November
2020
2020-11-01
2020-11-30
If I understand correctly, you want all the rows from the quarter in the data before a given quarter. You can filter and use dense_rank():
select s.*
from (select s.*,
dense_rank() over (order by year(start) desc, quarter(start) desc) as seqnum
from submissions s
where year(start) < #given_year or
(year(start) = #given_year and quarter(start) < #given_quarter)
) s
where seqnum = 1;
The above returns all rows from the previous quarter (which is what I thought you wanted). If you want only one row:
select s.*
from submissions s
where year(start) < #given_year or
(year(start) = #given_year and quarter(start) < #given_quarter)
order by start desc
limit 1;

ORDER BY MONTH(1) after GROUP_CONCAT as names?

If I don't use GROUP_CONCAT() then there is no difficulty to the group and order the rows according to date-month-year
Following code:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
21 12 2019 1092 1 pinky
04 01 2020 1050 1 harshit
30 12 2019 21 1 robin
05 01 2020 987 2 chetan
31 12 2019 1239 2 rahul
30 11 2019 157.5 1 rahul
01 01 2020 651 1 rahul
15 12 2019 1575 1 isha
03 01 2020 598.5 1 manvi
SEE the names are not concating
But as soon as I add this line:
GROUP_CONCAT(users.firstname SEPARATOR '-')) AS names
like this:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
GROUP_CONCAT(users.firstname SEPARATOR '-') AS names,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
01 01 2020 651 1 rahul
03 01 2020 598.5 1 manvi
04 01 2020 1050 1 harshit
05 01 2020 987 2 chetan-saurabh
15 12 2019 1575 1 isha
21 12 2019 1092 1 pinky
30 11 2019 157.5 1 rahul
30 12 2019 21 1 robin
31 12 2019 1239 2 rahul-manvi
then the order changed by day-order(without proper month and year order) but the grouping is correct.
Am I doing something wrong?
Use ORDER BY MONTH(orders.date_time). The problem is that your date column is not formatted as a valid MySQL date, so it's not extracting the month correctly.

MySQL String to DATE / TIME or TIMESTAMP

In my data set, the start and end time for a task is given as a string. The string contains:
'Day, Date Month YYYY HH:MM:SS GMT'
'Wed, 18 Oct 2017 10:11:03 GMT'
The previous questions on Stack Overflow do not have data in this format and I have been struggling how to convert it into DATE/TIME or TIMESTAMP. Any advice on this would be greatly appreciated!
This post was quite relevant but still does not meet my needs, as the format of the string is different in both cases:
Converting date/time string to unix timestamp in MySQL
Overall, I want to achieve a variable 'time_on_task' which takes the difference per person between their start_time and end_time. Thus, for the following data:
Person TaskID Start_time End_time
Alpha 1 'Wed, 18 Oct 2017 10:10:03 GMT' 'Wed. 18 Oct 2017 10:10:36 GMT'
Alpha 2 'Wed, 18 Oct 2017 10:11:16 GMT' 'Wed, 18 Oct 2017 10:11:28 GMT'
Beta 1 'Wed, 18 Oct 2017 10:12:03 GMT' 'Wed, 18 Oct 2017 10:12:49 GMT'
Alpha 3 'Wed, 18 Oct 2017 10:12:03 GMT' 'Wed, 18 Oct 2017 10:13:13 GMT'
Gamma 1 'Fri, 27 Oct 2017 22:57:12 GMT' 'Sat, 28 Oct 2017 02:00:54 GMT'
Beta 2 'Wed, 18 Oct 2017 10:13:40 GMT' 'Wed, 18 Oct 2017 10:14:03 GMT'
The required output would be something like this:
Person TaskID Time_on_task
Alpha 1 0:00:33 #['Wed, 18 Oct 2017 10:10:36 GMT' - 'Wed, 18 Oct 2017 10:10:03 GMT']
Alpha 2 0:00:12 #['Wed, 18 Oct 2017 10:11:28 GMT' - 'Wed, 18 Oct 2017 10:11:16 GMT']
Beta 1 0:00:46 #['Wed, 18 Oct 2017 10:12:49 GMT' - 'Wed, 18 Oct 2017 10:12:03 GMT']
Alpha 3 0:01:10 #['Sat, 18 Nov 2017 10:13:13 GMT' - 'Sat, 18 Nov 2017 10:12:03 GMT']
Gamma 1 3:03:42 #['Sat, 28 Oct 2017 02:00:54 GMT' - 'Fri, 27 Oct 2017 22:57:12 GMT']
Beta 2 0:00:23 #['Wed, 18 Oct 2017 10:14:03 GMT' - 'Wed, 18 Oct 2017 10:13:40 GMT']
You need STR_TO_DATE() to convert the string to a date. Consider:
select str_to_date(
'Wed, 18 Oct 2017 10:11:03 GMT',
'%a, %d %b %Y %T GMT'
)
Yields:
2017-10-18 10:11:03
Once you strings are converted to dates, you can use timestampdiff() to compute the difference between them, and turn the result back to a time using sec_to_time():
select
person,
taskID,
sec_to_time(
timestampdiff(
second,
str_to_date(Start_time, '%a, %d %b %Y %T GMT'),
str_to_date(End_time, '%a, %d %b %Y %T GMT')
)
) time_on_task
from mytable
Demo on DB Fiddlde:
| person | taskID | time_on_task |
| ------ | ------ | ------------ |
| Alpha | 1 | 00:00:33 |
| Alpha | 2 | 00:00:12 |
| Beta | 1 | 00:00:46 |
| Alpha | 3 | 00:01:10 |
| Gamma | 1 | 03:03:42 |
| Beta | 2 | 00:00:23 |

SQL return last 12 weeks data, grouped by week, starting last Monday

I've been working on a MySQL query that sorts data into weeks but I just can't figure out how to do it.
I would like to sort the data into weeks for the current and last 11 weeks. Each week will run from Monday 00:00:00 to Sunday 23:59:59.
(Taking todays date as 2014-12-04)...
Week 1: 2014-12-01 > 2014-12-07 - (Last Monday 00:00:00 to next Sunday 23:59:59)
Week 2: 2014-11-24 > 2014-11-30 - (Monday before last 00:00:00 to last Sunday 23:59:59)
Week 3: 2014-11-17 > 2014-11-23 - (Monday before before last 00:00:00 to last last Sunday 23:59:59)
And so on...
For each week the value field data will be totalled.
I need the data returned to be in the format:
datetime: The first date (Always a Monday) of that week.
value: The total of all the values in that week.
For example, the returned data:
Week 1: 2014-12-01 : Totalled value=11
Week 2: 2014-11-24 : Totalled value=3
Week 3: 2014-11-17 : Totalled value=9
Week 4: 2014-11-10 : Totalled value=7
Table_1 data:
table1id datetime value
1 2014-09-01 06:00:00 4
2 2014-09-04 17:00:00 6
3 2014-09-09 18:00:00 9
4 2014-09-15 07:00:00 4
5 2014-09-20 10:00:00 2
6 2014-09-25 10:00:00 3
7 2014-09-30 09:00:00 8
8 2014-10-01 14:00:00 5
9 2014-10-05 10:00:00 7
10 2014-10-09 18:00:00 3
11 2014-10-15 05:00:00 4
12 2014-10-20 07:00:00 8
13 2014-10-24 16:00:00 9
14 2014-10-29 15:00:00 5
15 2014-10-31 16:00:00 7
16 2014-11-05 09:00:00 2
17 2014-11-10 08:00:00 4
18 2014-11-15 16:00:00 3
19 2014-11-20 10:00:00 9
20 2014-11-25 10:00:00 2
21 2014-11-30 10:00:00 1
22 2014-12-01 15:00:00 7
23 2014-12-04 18:00:00 2
I 'could' just pull all the data unsorted for the date range using PHP and sort it from there but I'd rather the MySQL server do it.
Any suggestions would be greatly appreciated. :-)
based on generate days from date range
you can do smething like that:
select mondays.week, mondays.day, sum(value)
from
(select a.a+1 week, curdate() - WEEKDAY(curdate()) - INTERVAL (7*a.a) DAY as day from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9 union all select 10 union all select 11) as a) as mondays,
Table_1
where Table_1.datetime between mondays.day and (mondays.day + interval(7) day)
group by mondays.week, mondays.day;