Consecutive dates Sequence by criteria - mysql

I have a table that holds tasks like the following example:
id user_id project_id done_at duration type
1 13 15 2014-08-11 03:00:00 1
2 13 15 2014-08-11 04:00:00 1
10 13 15 2014-08-12 04:00:00 1
3 13 15 2014-08-12 08:00:00 2
5 13 13 2014-08-13 08:00:00 1
7 13 15 2014-08-14 04:00:00 1
8 13 15 2014-08-18 08:00:00 1
9 13 15 2014-08-19 08:00:00 2
How can i get start/end sequences of consecutive done_at column by user, project and type like this:
user_id project_id type start_done_at end_done_at duration
13 15 1 2014-08-11 2014-08-12 11:00:00
13 15 2 2014-08-12 2014-08-12 08:00:00
13 13 1 2014-08-13 2014-08-14 12:00:00
13 15 1 2014-08-18 2014-08-18 08:00:00
13 15 2 2014-08-19 2014-08-19 08:00:00
I already tried following this example: http://www.artfulsoftware.com/infotree/qrytip.php?id=76 however i didnt make to get the duration correctly.
My current query is this:
SELECT task.user_id as user_id, task.done_at as start_done_at, MIN(task2.done_at) as end_done_at, task.project_id as project_id, task.timeoff_type_id as timeoff_type, SEC_TO_TIME(SUM(TIME_TO_SEC(task.duration))) as duration
FROM tasks task
LEFT JOIN tasks task1 ON task.done_at = task1.done_at + 1
AND task.user_id = task1.user_id
AND task.project_id = task1.project_id
AND task.timeoff_type_id = task1.timeoff_type_id
LEFT JOIN tasks task2 ON task.done_at <= task2.done_at
AND task.user_id = task2.user_id
AND task.project_id = task2.project_id
AND task.timeoff_type_id = task2.timeoff_type_id
LEFT JOIN tasks task3 ON task2.done_at = task3.done_at -1
AND task2.user_id = task3.user_id
AND task2.project_id = task3.project_id
AND task2.timeoff_type_id = task3.timeoff_type_id
WHERE task1.done_at IS NULL
AND task2.done_at IS NOT NULL
AND task3.done_at IS NULL
GROUP BY task.user_id, task.project_id, task.timeoff_type_id, task.done_at

select
user_id, project_id,
min(done_at) as start_done_at,
max(done_at) as end_done_at,
sec_to_time(sum(time_to_sec(duration))) as duration
from (
select
t.*,
#gn := if(timestampdiff(day, #prev_date, done_at) between 0 and 1 and #prev_type = type and #prev_project = project_id, #gn, #gn + 1) as group_number,
#prev_date := done_at,
#prev_type := type,
#prev_project := project_id
from
t
, (select #prev_project := null, #prev_date := null, #prev_type := null, #gn := 0) var_init
order by project_id, done_at, duration
) sq
group by group_number
see it working live in an sqlfiddle

Related

Select N entries for each month value

I have the following SQL table:
Id DateTime Speed
1 2017-03-02 19:06:20 50
1 2017-03-02 19:10:18 52
1 2017-04-01 20:01:10 55
2 2017-03-02 18:06:20 60
2 2017-05-03 19:08:00 61
3 2017-04-12 19:01:40 80
3 2017-05-11 19:05:50 82
3 2017-05-14 11:00:00 81
I want to select any 2 entries for each month, so that months 3, 4 and 5 would have 2 observations.
Can anyone help with how to do it?
EXPECTED RESULT:
Id DateTime Speed
1 2017-03-02 19:06:20 50
1 2017-03-02 19:10:18 52
1 2017-04-01 20:01:10 55
3 2017-04-12 19:01:40 80
2 2017-05-03 19:08:00 61
3 2017-05-11 19:05:50 82
I think the most efficient general method in MySQL is to use variables:
select t.*
from (select t.*,
(#rn := if(#ym = date_format(date, '%Y-%m'), #rn + 1,
if(#ym := date_format(date, '%Y-%m'), 1, 1)
)
) as rn
from t cross join
(select #ym := '', #rn := 0) params
order by date_format(date, '%Y-%m')
) t
where rn <= 2;
This returns an arbitrary two rows from each month. You can add a second join key to get two particular values -- the first two, last two, highest speed or whatever.

How to make blank/missing in Date_time column if the no.of frozen/repeating Date_time

How to make blank/missing in Date_time column if the no.of frozen/repeating Date_time is equal to the no of desired Date_time record between previous correct Date_time and next correct Date_time in the time series (ROW_ID : 5,6,12,13)- Replace the frozen Date_time with the missing Date_time and keep record.
WE have the data in 15 mins interval
INPUT:
Row_id Name Date_time Value
1 US 01-Nov-16 04:15:00 12
2 US 01-Nov-16 04:30:00 15
3 US 01-Nov-16 04:45:00 17
4 US 01-Nov-16 05:00:00 19
5 US 01-Nov-16 05:15:00 21
6 US 01-Nov-16 05:15:00 23
7 US 01-Nov-16 05:45:00 25
8 UK 06-Dec-16 09:15:00 27
9 UK 06-Dec-16 09:30:00 29
10 UK 06-Dec-16 09:45:00 31
11 UK 06-Dec-16 10:00:00 33
12 UK 06-Dec-16 10:15:00 35
13 UK 06-Dec-16 10:15:00 37
14 UK 06-Dec-16 10:45:00 39
OUTPUT:
Row_id Name Date_time Value
1 US 01-Nov-16 04:15:00 12
2 US 01-Nov-16 04:30:00 15
3 US 01-Nov-16 04:45:00 17
4 US 01-Nov-16 05:00:00 19
5 US 21
6 US 23
7 US 01-Nov-16 05:45:00 25
8 UK 06-Dec-16 09:15:00 27
9 UK 06-Dec-16 09:30:00 29
10 UK 06-Dec-16 09:45:00 31
11 UK 06-Dec-16 10:00:00 33
12 UK 35
13 UK 37
14 UK 06-Dec-16 10:45:00 39
I have tried to get the output with below code
create table DS2 as
SELECT date_time,value, name, COUNT() - 2
FROM (
SELECT date_time,value, name, rn - seq AS grp
FROM (
SELECT date_time,value, name,
#rn := #rn + 1 AS rn,
#seq := IF(#name = name And #val = date_time, #seq+1, 1) AS seq,
#name := name,
#val := date_time
FROM DS1
CROSS JOIN (SELECT #rn := 0, #seq := 0, #name = '', #val = 0) AS vars
ORDER BY date) AS t ) AS s
GROUP BY date_time, name, grp
HAVING COUNT() > 2
;
Thanks in advance.

Get the latest record for each employee older than a given date

I have a status history table that also includes future dated records.
Example: employee_jobs
id | employee_id | division_id | department_id | job_id | effective_date
1 100 1 1 1 2015-01-01
2 100 1 1 2 2016-01-01
3 100 1 2 4 2017-01-01
4 200 1 3 5 2016-01-01
5 300 1 3 6 2015-01-01
6 300 1 3 7 2016-05-25
I need a preforming SQL that will show a given employee_id's current live record when given a date: Example Date = 2016-08-15
The result set should be:
id | employee_id | division_id | department_id | job_id | effective_date
2 100 1 1 2 2016-01-01
4 200 1 3 5 2016-01-01
6 300 1 3 7 2016-05-25
I guess you want records for each employee having the latest effective_date with a constraint
(effective_date must be less than or equal to a given date)
SELECT
*
FROM
(
SELECT
*,
IF(#sameEmployee = employee_id, #rn := #rn + 1,
IF(#sameEmployee := employee_id, #rn := 1, #rn := 1)
) AS row_number
FROM employee_jobs
CROSS JOIN (SELECT #sameEmployee := 0, #rn := 1) var
WHERE effective_date <= '2016-08-15'
ORDER BY employee_id, effective_date DESC
) AS t
WHERE t.row_number = 1
ORDER BY t.employee_id

Max(Date) query with another condition

my record:
SF_ID CardID Status Received_Date Meetup_Date
12 1 Yes 2015-01-12 2015-12-03
13 1 No 2015-12-01 NULL
14 1 No 2015-12-01 NULL
15 2 No 2015-12-02 NULL
16 2 No 2015-12-02 NULL
17 3 No 2015-12-01 NULL
18 4 No 2015-12-06 NULL
19 5 Yes 2015-11-30 2015-12-01
20 5 No 2015-11-30 NULL
22 5 No 2015-11-30 NULL
23 7 yes 2015-12-06 2015-12-07
Requirement #1:
all cardID where Received_Date is Minimum and Status
is No and Top 01 SF_ID. I've tried it in the following way without success:
SELECT CardSFID,
CardID,
CardSFShortDate
FROM CC_Shortfall AS [data]
WHERE ( CardSFShortDate = (SELECT TOP 1 PERCENT CardSFShortDate
FROM CC_Shortfall
WHERE CardID = [data].CardID) )
AND CardSFYesNo = 'No'
Requirement #2:
all cardID Where MeetUp_Date is Maximum and Status
is Yes and there are not any No Status under CardID
i've tried to do it in the following way without succcess:
SELECT CardSFID,
CardID,
CardSfShortRcvDate
FROM CC_Shortfall AS [data]
WHERE ( CardSfShortRcvDate = (SELECT Max(CardSfShortRcvDate)
FROM CC_Shortfall
WHERE CardID = [data].CardID) )
AND CardSFYesNo = 'Yes'

Select multiple fields from subquery

I have the next query:
SELECT
a.Date,
(SELECT SUM(Used), SUM(Max) FROM Switch_Statistic b WHERE Date = (SELECT MAX(Date) FROM Switch_Statistic WHERE Switch_ID = b.Switch_ID AND Date <= a.Date))
FROM Switch_Statistic a
GROUP BY Date;
As you see I need to select SUM(Used), SUM(Max) from subquery. With CONCAT is not good solution!
Table schema:
ID --- Switch_ID --- Date --- Max --- Used
Some data:
1 641 2014-10-04 2 16
20 630 2014-10-04 1 7
24 634 2014-10-04 0 8
26 641 2014-10-06 2 16
32 641 2014-10-07 2 16
35 641 2014-10-08 3 16
39 641 2014-10-09 2 16
64 293 2014-10-10 1 22
...
557 38 2014-10-12 3 22
559 293 2014-10-12 1 22
563 294 2014-10-12 6 22
565 641 2014-10-12 2 16
What I need:
Example with CONCAT_WS
mysql> SELECT
a.Date,
(SELECT CONCAT_WS('/', SUM(Used), SUM(Max)) FROM Switch_Statistic b WHERE Date = (SELECT MAX(Date) FROM Switch_Statistic WHERE Switch_ID = b.Switch_ID AND Date <= a.Date)) AS Result
FROM Switch_Statistic a
GROUP BY Date;
+------------+----------+
| Date | Result |
+------------+----------+
| 2014-10-04 | 3/31 |
| 2014-10-06 | 3/31 |
| 2014-10-07 | 3/31 |
| 2014-10-08 | 4/31 |
| 2014-10-09 | 3/31 |
| 2014-10-10 | 249/1587 |
| 2014-10-11 | 354/2147 |
| 2014-10-12 | 360/2185 |
+------------+----------+
8 rows in set (0.26 sec)
Query logic:
1) Select all date's from table
2) SUM - Used and Max for current date, if Switch_ID don't have record for this date, then select the last which exists in table
Link to sqlfiddle - http://sqlfiddle.com/#!2/c3d479
You should be able to do this with just aggregation and no subqueries or joins:
SELECT date, sum(used) as used, sum(max) as max
FROM switch_statistic ss
where ss.date = (select max(date) from Switch_Statistics ss2 where ss2.Switch_id = ss.SwitchId
GROUP BY ss.date;
EDIT:
You seem to want a cumulative sum. In MySQL, this is often best done using variables:
SELECT date, used, max, (#u := #u + used) as cumeused, #m := #m + max) as cumemax
fROM (SELECT date, sum(used) as used, sum(max) as max
FROM switch_statistic ss
GROUP BY ss.date
) ss CROSS JOIN
(SELECT #u := 0, #m := 0) vars
ORDER BY date;