From here, I modified the query slightly to get
select adddate('2015-02-01', numlist.id) as `my_date`,
weekday(adddate('2015-02-01', numlist.id)) as day_no,
dayname(adddate('2015-02-01', numlist.id)) as `day_name`
from
(SELECT n1.i + n10.i*10 + n100.i*100 AS id
FROM num n1 cross join num as n10 cross join num as n100) as numlist
where adddate('2015-02-01', numlist.id) <= '2015-02-28'
and dayname(adddate('2015-02-01', numlist.id)) in( 'Monday', 'Tuesday');
which gives
+------------+--------+----------+
| my_date | day_no | day_name |
+------------+--------+----------+
| 2015-02-02 | 0 | Monday |
| 2015-02-03 | 1 | Tuesday |
| 2015-02-09 | 0 | Monday |
| 2015-02-10 | 1 | Tuesday |
| 2015-02-16 | 0 | Monday |
| 2015-02-17 | 1 | Tuesday |
| 2015-02-23 | 0 | Monday |
| 2015-02-24 | 1 | Tuesday |
+------------+--------+----------+
8 rows in set (0.01 sec)
or from here
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) selected_date from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where selected_date between '2015-02-01' and '2015-02-28'
and dayname(selected_date) in ('Monday', 'Tuesday');
result
+---------------+
| selected_date |
+---------------+
| 2015-02-02 |
| 2015-02-03 |
| 2015-02-09 |
| 2015-02-10 |
| 2015-02-16 |
| 2015-02-17 |
| 2015-02-23 |
| 2015-02-24 |
+---------------+
8 rows in set (0.23 sec)
CREATE TABLE mydate( blah date);
INSERT INTO mydate (blah)
select adddate('2015-02-01', numlist.id) as `my_date`
-- weekday(adddate('2015-02-01', numlist.id)) as day_no,
-- dayname(adddate('2015-02-01', numlist.id)) as `day_name`
from
(SELECT n1.i + n10.i*10 + n100.i*100 AS id
FROM num n1 cross join num as n10 cross join num as n100) as numlist
where adddate('2015-02-01', numlist.id) <= '2015-05-28'
and dayname(adddate('2015-02-01', numlist.id)) in( 'Monday', 'Tuesday');
(need a table num)
mysql> select * from mydate;
+------------+
| blah |
+------------+
| 2015-02-02 |
| 2015-02-03 |
| 2015-02-09 |
| 2015-02-10 |
| 2015-02-16 |
| 2015-02-17 |
| 2015-02-23 |
| 2015-02-24 |
| 2015-03-02 |
OR
insert into mydate (blah)
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) selected_date from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where selected_date between '2015-02-01' and '2015-05-28'
and dayname(selected_date) in ('Monday', 'Tuesday');
No table necessary. Same result as above.
If you need only the initial and the last (current) value of TimeWorked
, you only need to add GROUP BY
(ticket) to your query:
-- query 1
SELECT
ti.id AS Ticket,
ti.Subject AS Subject,
SUM(tr.NewValue - tr.OldValue) AS TransactionTimeWorkedTotal,
ti.TimeWorked - SUM(tr.NewValue - tr.OldValue) AS InitialTimeWorked,
ti.Created AS TicketCreated
FROM
Tickets AS ti
LEFT JOIN Transactions AS tr ON ti.id = tr.ObjectId
AND tr.Field = 'TimeWorked'
WHERE
ti.Queue = 50
AND ti.Created > '2015-06-01'
AND ti.Created < '2015-09-01'
GROUP BY
ti.id,
ti.Subject,
ti.TimeWorked,
ti.Created ;
This could also be accomplished with a different approach:
-- query 2
SELECT
ti.id AS Ticket,
ti.Subject AS Subject,
COALESCE(ti.TimeWorked - tri.OldValue, 0) AS TransactionTimeWorkedTotal,
COALESCE(tr.OldValue, ti.TimeWorked) AS InitialTimeWorked,
ti.Created AS TicketCreated
FROM
Tickets AS ti
LEFT JOIN Transactions AS tr
ON ti.id = tr.ObjectId
AND tr.Field = 'TimeWorked'
AND tr.Created =
( SELECT tr1.Created -- finds the first
FROM Transactions AS tr1 -- transaction (if any)
WHERE ti.id = tr1.ObjectId -- for the ticket
AND tr1.Field = 'TimeWorked'
ORDER BY tr1.Created
LIMIT 1
)
WHERE
ti.Queue = 50
AND ti.Created > '2015-06-01'
AND ti.Created < '2015-09-01' ;
Both the above queries will give the initial TimeWorked
and the total of the transactions TimeWorked
values.
If you want all the individual changes as well - and since the Transactions
table has already the old and new values - it needs something different, but not more complicated than the previous queries. using query 2 for example:
-- query 2b
SELECT
ti.id AS Ticket,
ti.Subject AS Subject,
NULL AS TransactionTimeWorked,
COALESCE(tr.OldValue, ti.TimeWorked) AS InitialTimeWorked,
ti.Created AS TicketCreated,
ti.Created AS TransactionCreated
FROM
Tickets AS ti
LEFT JOIN Transactions AS tr
ON ti.id = tr.ObjectId
AND tr.Field = 'TimeWorked'
AND tr.Created =
( SELECT tr1.Created -- finds the first
FROM Transactions AS tr1 -- transaction (if any)
WHERE ti.id = tr1.ObjectId -- for the ticket
AND tr1.Field = 'TimeWorked'
ORDER BY tr1.Created
LIMIT 1
)
WHERE
ti.Queue = 50
AND ti.Created > '2015-06-01'
AND ti.Created < '2015-09-01'
UNION ALL
SELECT
ti.id AS Ticket,
ti.Subject AS Subject,
tr.NewValue - tr.OldValue AS TransactionTimeWorked,
NULL AS InitialTimeWorked,
ti.Created AS TicketCreated,
tr.Created AS TransactionCreated
FROM
Tickets AS ti
INNER JOIN Transactions AS tr -- all the transactions
ON ti.id = tr.ObjectId -- of a ticket
AND tr.Field = 'TimeWorked'
WHERE
ti.Queue = 50
AND ti.Created > '2015-06-01'
AND ti.Created < '2015-09-01'
ORDER BY
Ticket,
TransactionCreated ;
Best Answer
I can give you some guidance, at a minimum. I don't use MySQL in detail, but in general:
Step 1: get the date ranges
I assume that for each row returned from
mytable
that you want the date in that row as a start date, and the date in the following row as the end date. Check MySQL documentation on "windowing functions" (related to aggregate functions). There may be a function that can do this for you (in SQL Server, the function isLEAD
. If you can't find that, you can always do a subquery in each row, returning the smallest date (matching the same criteria) bigger than the date in the current row. This would look something like:(Exact syntax may be different).
Step 2: Get the
SUM
sGiven that we have the start and end dates for each range, getting the
SUM
of the age ranges is fairly easy. We join the query we did above againstTable2
and useGROUP BY
andSUM
. I assume that dates that fall on a boundary should not be included in both groups, so we'll toss them into the later group:(Again, syntax may need adjusting for MySQL). Note that this does not sum up ages for any dates either before the first date, or on or after the last date, as those are not part of valid ranges.
Hope this helps point you in the right direction.