Mysql - sql query to get next class based on date - mysql

I have the following data in my webinar_timing table in mysql database
start_time and end_time are of type datetime
id | webinar_id | start_time | end_time
-------------------------------------------------------------------
1 | 5 | 3/18/2015 6:00:00 PM | 3/18/2015 7:00:00 PM
2 | 5 | 3/19/2015 6:00:00 PM | 3/19/2015 7:00:00 PM
3 | 5 | 3/20/2015 6:00:00 PM | 3/20/2015 7:00:00 PM
4 | 5 | 3/21/2015 6:00:00 PM | 3/21/2015 7:00:00 PM
5 | 5 | 3/22/2015 6:00:00 PM | 3/22/2015 7:00:00 PM
6 | 11 | 3/20/2015 8:00:00 PM | 3/20/2015 9:00:00 PM
7 | 11 | 3/21/2015 8:00:00 PM | 3/21/2015 9:00:00 PM
8 | 11 | 3/22/2015 8:00:00 PM | 3/22/2015 9:00:00 PM
9 | 22 | 3/25/2015 8:00:00 PM | 3/25/2015 9:00:00 PM
10 | 22 | 3/27/2015 8:00:00 PM | 3/27/2015 9:00:00 PM
11 | 22 | 3/29/2015 8:00:00 PM | 3/27/2015 9:00:00 PM
Basically, for each webinar, I want the total occurences and number of classes completed or remaining AND the NEXT upcoming class
Egs: When I run this query say at 3/21/2015 at 4:00 PM - this is the result I am expecting
webinar_id | total | Classes Completed | Next Class
----------------------------------------------------------
5 | 5 | 3 | 3/21/2015 6:00:00 PM
11 | 3 | 1 | 3/21/2015 8:00:00 PM
22 | 3 | 0 | 3/25/2015 8:00:00 PM
OR
webinar_id | total | Classes Remaining | Next Class
----------------------------------------------------------
5 | 5 | 2 | 3/21/2015 6:00:00 PM
11 | 3 | 2 | 3/21/2015 8:00:00 PM
22 | 3 | 3 | 3/25/2015 8:00:00 PM
Based on a previous question - a fellow SO Peter assisted with the following
select webinar_id, count(*) AS total,
SUM(IF(end_time<NOW(), 1, 0)) AS completed,
SUM(IF(start_time>=NOW(), 1, 0)) AS remaining
from webinar_times
group by webinar_id;
SQL Fiddle
http://sqlfiddle.com/#!9/c4e71/1
Any help will be appreciated
Thanks in advance

Something like:
select webinar_id
, count(*) AS total
, count(case when end_time<NOW() then 1 end) as completed
, (select count(1)
from webinar_times y
where x.webinar_id = y.webinar_id
and y.start_time > NOW()) as remaining
, min(case when x.start_time > NOW() then x.start_time end) as next_class
from webinar_times x
group by webinar_id;
should do
EDIT: realized that the sub-select is un-necessary:
select webinar_id
, count(*) AS total
, count(case when end_time<NOW() then 1 end) as completed
, count(case when start_time>NOW() then 1 end) as remaining
, min(case when x.start_time > NOW() then x.start_time end) as next_class
from webinar_times x
group by webinar_id;

You can make an outer join between two grouped queries, e.g. one that counts the total number of webinars and another that both counts the remaining webinars and obtains the start time of the next one:
SELECT * FROM (
SELECT webinar_id, COUNT(*) total
FROM webinar_times
GROUP BY webinar_id
) totals NATURAL LEFT JOIN (
SELECT webinar_id, COUNT(*) remaining, MIN(start_time) next
FROM webinar_times
WHERE start_time > NOW()
GROUP BY webinar_id
) future
See it on sqlfiddle:
+------------+-------+-----------+-------------------------+
| webinar_id | total | remaining | next |
+------------+-------+-----------+-------------------------+
| 6 | 5 | 1 | March, 22 2015 06:00:00 |
| 11 | 3 | 1 | March, 22 2015 07:00:00 |
| 22 | 3 | 3 | March, 25 2015 07:00:00 |
+------------+-------+-----------+-------------------------+
A composite index defined over (webinar_id, start_time) would benefit this query, and avoids the full table scans that the approach outlined in your question would otherwise require.

Consider the following example and this will give you what you need
mysql> create table test (id int, webinar_id int, start_time datetime);
Query OK, 0 rows affected (0.16 sec)
mysql> insert into test values (1,5,'2015-03-18 18:00:00'),
(2,5,'2015-03-19 18:00:00'),
(3,5,'2015-03-20 18:00:00'),
(4,5,'2015-03-21 18:00:00'),
(5,5,'2015-03-21 18:00:00'),
(6,11,'2015-03-20 20:00:00'),
(7,11,'2015-03-21 20:00:00'),
(8,11,'2015-03-22 20:00:00'),
(9,22,'2015-03-25 20:00:00'),
(10,22,'2015-03-27 20:00:00'),
(11,22,'2015-03-29 20:00:00');
Query OK, 11 rows affected (0.05 sec)
Records: 11 Duplicates: 0 Warnings: 0
mysql> select * from test ;
+------+------------+---------------------+
| id | webinar_id | start_time |
+------+------------+---------------------+
| 1 | 5 | 2015-03-18 18:00:00 |
| 2 | 5 | 2015-03-19 18:00:00 |
| 3 | 5 | 2015-03-20 18:00:00 |
| 4 | 5 | 2015-03-21 18:00:00 |
| 5 | 5 | 2015-03-21 18:00:00 |
| 6 | 11 | 2015-03-20 20:00:00 |
| 7 | 11 | 2015-03-21 20:00:00 |
| 8 | 11 | 2015-03-22 20:00:00 |
| 9 | 22 | 2015-03-25 20:00:00 |
| 10 | 22 | 2015-03-27 20:00:00 |
| 11 | 22 | 2015-03-29 20:00:00 |
+------+------------+---------------------+
11 rows in set (0.00 sec)
select
t.webinar_id,
count(*) as total,
sum( case when t.start_time < now() then 1 else 0 end) as completed ,
sum( case when t.start_time > now() then 1 else 0 end) as remaining,
t1.next_date from test t
join (
select
webinar_id,
min(start_time) as next_date
from test where start_time > now()
group by webinar_id
)t1 on t.webinar_id= t1.webinar_id
group by t.webinar_id;
+------------+-------+-----------+-----------+---------------------+
| webinar_id | total | completed | remaining | next_date |
+------------+-------+-----------+-----------+---------------------+
| 5 | 5 | 3 | 2 | 2015-03-21 18:00:00 |
| 11 | 3 | 1 | 2 | 2015-03-21 20:00:00 |
| 22 | 3 | 0 | 3 | 2015-03-25 20:00:00 |
+------------+-------+-----------+-----------+---------------------+
3 rows in set (0.00 sec)

Related

MySQL Query to get the monthly data difference

select * from new_joiner;
+------+--------------+
| id | date_of_join |
+------+--------------+
| 1 | 2020-01-10 |
| 2 | 2020-01-02 |
| 3 | 2020-01-05 |
| 4 | 2020-02-10 |
| 5 | 2020-02-11 |
| 6 | 2020-07-11 |
| 7 | 2020-07-11 |
| 8 | 2020-07-11 |
| 9 | 2020-07-11 |
| 10 | 2020-07-11 |
| 11 | 2020-05-01 |
| 12 | 2020-05-02 |
| 13 | 2020-05-03 |
| 14 | 2020-05-04 |
| 15 | 2020-05-05 |
| 16 | 2020-05-05 |
| 17 | 2020-05-06 |
+------+--------------+
select MONTHNAME(date_of_join) as MONTHNAME,
count(id) as JOINEE
from new_joiner
where MONTH(date_of_join)>=1
group by MONTH(date_of_join);
+-----------+--------+
| MONTHNAME | JOINEE |
+-----------+--------+
| January | 3 |
| February | 2 |
| May | 7 |
| July | 5 |
+-----------+--------+
I want a query that gives me the monthly data change compare to previous month.
For example: new joinee in Jan was 3, and in Feb it was 2, so compare to Jan in Feb month -1 joined, so the query should output me:
+-----------+-------------+
| MONTHNAME | JOINEE_DIFF |
+-----------+-------------+
| February | -1 |
| Mar | -2 |
| April | 0 |
| May | 7 |
| June | -7 |
| July | 5 |
| Aug | -5 |
| Sep | 0 |
| Oct | 0 |
| Nov | 0 |
| Dec | 0 |
+-----------+-------------+
Ignore Jan as it doesn't have a previous month and assume we have data only for a given year say 2020. Require data for all months from Feb to Dec.
Assuming you have data for every month, you can use lag():
select MONTHNAME(date_of_join) as MONTHNAME,
count(id) as JOINEE,
(count(*) - lag(count(*)) over (order by min(date_of_join)) as diff
from new_joiner
where MONTH(date_of_join) >= 1
group by MONTH(date_of_join);
Note that using months without years if fraught with peril. Also, the month() of any well-formed date should be larger than 1.
All this suggests a query more like:
select *
from (select MONTHNAME(date_of_join) as MONTHNAME,
count(id) as JOINEE,
(count(*) - lag(count(*)) over (order by min(date_of_join)) as diff,
min(date_of_join) as min_date_of_join
from new_joiner
where date_of_join >= '2020-01-01' and date_of_join < '2021-01-01'
group by MONTH(date_of_join)
) t
where diff is not null
order by min_date_of_join;
Use a correlated subquery to get the number of joinees of previous month and subtract it:
SELECT
t.monthname,
joinee - (SELECT COUNT(*) FROM new_joiner WHERE MONTH(date_of_join) = t.month - 1) JOINEE_DIFF
FROM (
SELECT MONTH(date_of_join) month, MONTHNAME(date_of_join) monthname,
COUNT(id) joinee
FROM new_joiner
GROUP BY month, monthname
) t
WHERE t.month > 1;

Get data for specific time range

I'm trying to select records between 7 pm to 7 am from 2018-09-24 until 2018-09-26 for each day.
example:
2018-09-24_____7 pm to 7 am____ 2018-09-25
2018-09-25_____7 pm to 7 am____ 2018-09-26
2018-09-26_____7 pm to 7am____ 2018-09-27
by using this code A: I get records from 7pm(2018-09-24) until 7am(2018-09-26).
If Trim(cbShift.Text) = "Morning" Then
startdt = (S_date.Text) & " 19:00:00.317"
enddt = (E_date.Text) & " 07:00:00.160" End If
SELECT FROM tb_test
WHERE (DateCreate BETWEEN convert(datetime,#startdt) AND convert(datetime,#enddt))
and by using this code B:
WHERE DateCreate > convert(datetime,'2018-09-24') AND DateCreate <=
DATEADD(day,1,convert(datetime,'2018-09-26'))
AND (DATEPART(hh,DateCreate) >= 19 and DATEPART(hh,DateCreate) <= 24 )
or DateCreate > convert(datetime,'2018-09-24') AND DateCreate <=
DATEADD(day,1,convert(datetime,'2018-09-26'))
AND (DATEPART(hh,DateCreate) >= 0 and DATEPART(hh,DateCreate) <= 6 )
I get
2018-09-24 (00->7 and 19 ->24) , 2018-09-25 (00->7 and 19 ->24), and 2018-09-26 (00->7 and 19 ->24)
Is there a way I can do to get a data exactly like my example above.
Thanks for your help
I think that the problem is with the order of evaluation in your WHERE clause. I always use brackets around OR operators in SQL. The following works on MySQL 5.6.
SELECT *
FROM tb_test
WHERE datecreate between '2018-09-24 19:00:00' and '2018-09-26 07:00:00'
AND (hour(DateCreate) >= 19 or hour(DateCreate) < 7);
For reference, I used this test schema:
CREATE table tb_test
(datecreate datetime);
CREATE OR REPLACE VIEW generator_16
AS 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 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL
SELECT 15;
CREATE OR REPLACE VIEW generator_256
AS SELECT ( ( hi.n << 4 ) | lo.n ) AS n
FROM generator_16 lo, generator_16 hi;
INSERT INTO tb_test
SELECT date_add("2018-09-24",interval n hour)
FROM generator_256;
Another way to look at the problem is to say that you want DateCreate -12 hours to be between 7am and 7pm on the days of interest. So, try this (note we don't add times to startdt and enddt):
If Trim(cbShift.Text) = "Morning" Then
startdt = (S_date.Text)
enddt = (E_date.Text) End If
SELECT FROM tb_test
WHERE DateCreate - INTERVAL 12 HOUR BETWEEN CONVERT(DATETIME,#startdt) AND CONVERT(DATETIME,#enddt) AND
TIME(DateCreate - INTERVAL 12 HOUR) BETWEEN '07:00:00' AND '19:00:00'
Let's create some test data:
mysql> create table t (id int auto_increment, stamp datetime, primary key (id));
Query OK, 0 rows affected (0.46 sec)
mysql> insert into t (stamp) values
-> ('2018-09-24 18:59:59'), ('2018-09-24 19:00:00'), ('2018-09-24 19:00:01'),
-> ('2018-09-25 06:59:59'), ('2018-09-25 07:00:00'), ('2018-09-25 07:00:01'),
-> ('2018-09-25 18:59:59'), ('2018-09-25 19:00:00'), ('2018-09-25 19:00:01'),
-> ('2018-09-26 06:59:59'), ('2018-09-26 07:00:00'), ('2018-09-26 07:00:01'),
-> ('2018-09-26 18:59:59'), ('2018-09-26 19:00:00'), ('2018-09-26 19:00:01'),
-> ('2018-09-27 06:59:59'), ('2018-09-27 07:00:00'), ('2018-09-27 07:00:01');
Query OK, 18 rows affected (0.00 sec)
Records: 18 Duplicates: 0 Warnings: 0
mysql> select * from t;
+----+---------------------+
| id | stamp |
+----+---------------------+
| 1 | 2018-09-24 18:59:59 |
| 2 | 2018-09-24 19:00:00 |
| 3 | 2018-09-24 19:00:01 |
| 4 | 2018-09-25 06:59:59 |
| 5 | 2018-09-25 07:00:00 |
| 6 | 2018-09-25 07:00:01 |
| 7 | 2018-09-25 18:59:59 |
| 8 | 2018-09-25 19:00:00 |
| 9 | 2018-09-25 19:00:01 |
| 10 | 2018-09-26 06:59:59 |
| 11 | 2018-09-26 07:00:00 |
| 12 | 2018-09-26 07:00:01 |
| 13 | 2018-09-26 18:59:59 |
| 14 | 2018-09-26 19:00:00 |
| 15 | 2018-09-26 19:00:01 |
| 16 | 2018-09-27 06:59:59 |
| 17 | 2018-09-27 07:00:00 |
| 18 | 2018-09-27 07:00:01 |
+----+---------------------+
18 rows in set (0.00 sec)
Now, we want to select out from 2018-09-24 19:00:00 to 2018-09-25 07:00:00:
mysql> select * from t where stamp between (#start := '2018-09-24 19:00:00') and date_add(#start, interval 12 hour);
+----+---------------------+
| id | stamp |
+----+---------------------+
| 2 | 2018-09-24 19:00:00 |
| 3 | 2018-09-24 19:00:01 |
| 4 | 2018-09-25 06:59:59 |
| 5 | 2018-09-25 07:00:00 |
+----+---------------------+
4 rows in set (0.01 sec)
If we want to include 3 days worth of data during those windows, we can do this using UNION ALL:
mysql> select * from t where stamp between (#start := '2018-09-24 19:00:00') and date_add(#start, interval 12 hour)
-> union all select * from t where stamp between (#start := '2018-09-25 19:00:00') and date_add(#start, interval 12 hour)
-> union all select * from t where stamp between (#start := '2018-09-26 19:00:00') and date_add(#start, interval 12 hour);
+----+---------------------+
| id | stamp |
+----+---------------------+
| 2 | 2018-09-24 19:00:00 |
| 3 | 2018-09-24 19:00:01 |
| 4 | 2018-09-25 06:59:59 |
| 5 | 2018-09-25 07:00:00 |
| 8 | 2018-09-25 19:00:00 |
| 9 | 2018-09-25 19:00:01 |
| 10 | 2018-09-26 06:59:59 |
| 11 | 2018-09-26 07:00:00 |
| 14 | 2018-09-26 19:00:00 |
| 15 | 2018-09-26 19:00:01 |
| 16 | 2018-09-27 06:59:59 |
| 17 | 2018-09-27 07:00:00 |
+----+---------------------+
12 rows in set (0.00 sec)
And that's how it's done.
Edited to add: After seeing Nick's answer that uses TIME(), that's actually a cleaner solution:
mysql> select * from t where date(stamp) between '2018-09-24' and '2018-09-27'
-> and time(stamp + interval 12 hour) between '07:00:00' and '19:00:00';
+----+---------------------+
| id | stamp |
+----+---------------------+
| 2 | 2018-09-24 19:00:00 |
| 3 | 2018-09-24 19:00:01 |
| 4 | 2018-09-25 06:59:59 |
| 5 | 2018-09-25 07:00:00 |
| 8 | 2018-09-25 19:00:00 |
| 9 | 2018-09-25 19:00:01 |
| 10 | 2018-09-26 06:59:59 |
| 11 | 2018-09-26 07:00:00 |
| 14 | 2018-09-26 19:00:00 |
| 15 | 2018-09-26 19:00:01 |
| 16 | 2018-09-27 06:59:59 |
| 17 | 2018-09-27 07:00:00 |
+----+---------------------+
12 rows in set (0.00 sec)

MYSQL: Left JOIN from two SELECT to "fill gaps" in dates

Let's say I have a table "calendar"
+------------+
| day_date |
+------------+
| 2015-01-01 |
| 2015-01-02 |
| 2015-01-03 |
| .......... |
| 2015-07-14 |
| 2015-07-15 |
+------------+
With this query I can select the WEEK (that I need)
SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS YEAR,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start
FROM calendar
GROUP BY NUM_WEEK
And this is the result:
+----------+------+------------+
| NUM_WEEK | YEAR | date_start |
+----------+------+------------+
| 29 | 2015 | 2015-07-20 |
| 30 | 2015 | 2015-07-27 |
| 31 | 2015 | 2015-08-03 |
| 32 | 2015 | 2015-08-10 |
| 33 | 2015 | 2015-08-17 |
| 34 | 2015 | 2015-08-24 |
| 35 | 2015 | 2015-08-31 |
| 36 | 2015 | 2015-09-07 |
| 37 | 2015 | 2015-09-14 |
| 38 | 2015 | 2015-09-21 |
| 39 | 2015 | 2015-09-28 |
| 40 | 2015 | 2015-10-05 |
| 41 | 2015 | 2015-10-12 |
| 42 | 2015 | 2015-10-19 |
| 43 | 2015 | 2015-10-26 |
+----------+------+------------+
Now I have another table:
+----+------------+--------+---------------------+
| id | id_account | amount | date_transaction |
+----+------------+--------+---------------------+
| 1 | 283 | 150 | 2015-06-21 15:50:47 |
| 2 | 283 | 47.74 | 2015-07-23 15:55:44 |
| 3 | 281 | 21.55 | 2015-08-24 12:27:11 |
| 4 | 283 | 11.22 | 2015-08-25 10:00:54 |
+----+------------+--------+---------------------+
They are gaps in date.
With a similar query:
SELECT WEEK(date_transaction,1) AS NUM_WEEK,
YEAR(date_transaction) AS YEAR,
STR_TO_DATE(CONCAT(YEAR(date_transaction),WEEK(date_transaction,1),' Monday'), '%X%V %W')
AS date_start,
transaction.id_account,
SUM(amount) as total FROM transaction
INNER JOIN account ON account.id_account = transaction.id_account
WHERE amount > 0 AND transaction.id_account
IN ( SELECT id_account FROM account WHERE id_customer = 12 )
GROUP BY id_account, WEEK(date_transaction,1)
I obtain this result (probably data are not accurate, referring to previous tables, just to explain).
+----------+------+------------+-----------+----------+
| NUM_WEEK | YEAR | date_start | idAccount | total |
+----------+------+------------+-----------+----------+
| 29 | 2015 | 2015-07-20 | 281 | 22377.00 |
| 30 | 2015 | 2015-07-27 | 281 | 11550.00 |
| 32 | 2015 | 2015-08-04 | 281 | 4500.00 |
| 30 | 2015 | 2015-07-27 | 283 | 1500 |
+----------+------+------------+-----------+----------+
What I would, RIGHT (or LEFT) JOINING the two tables?
The min (and max) WEEK, so I can... (see 2)
Fill the gaps with missing WEEKS with NULL VALUES.
E.g., in a more complicated resultset:
+----------+------+------------+-----------+----------+
| NUM_WEEK | YEAR | date_start | idAccount | total |
+----------+------+------------+-----------+----------+
| 29 | 2015 | 2015-07-20 | 281 | 22377.00 |
| 30 | 2015 | 2015-07-27 | 281 | 11550.00 |
| 31 | 2015 | 2015-07-02 | 281 | NULL |
| 32 | 2015 | 2015-08-09 | 281 | 4500.00 |
| 29 | 2015 | 2015-08-09 | 283 | NULL |
| 30 | 2015 | 2015-07-16 | 283 | 1500 |
| 31 | 2015 | 2015-07-16 | 283 | NULL |
| 32 | 2015 | 2015-07-16 | 283 | NULL |
+----------+------+------------+-----------+----------+
Note, for example, that id=283 now has NULL at WEEK 29, 31 and 32, for example, like id=281 has NULL in WEEK 31.
I prepared also SQLFiddle here: http://sqlfiddle.com/#!9/a8fdc/3
Thank you very much.
I take a look on your question and i came up with this solution. Here is how your query could look like:
SELECT t1.NUM_WEEK, t1.`YEAR`, t1.date_start, t1.id_account, t2.total
FROM (SELECT c.NUM_WEEK, c.`YEAR`, c.date_start, a.id_account
FROM (SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK) c
INNER JOIN account a
ON FIND_IN_SET(a.id_account, c.accounts_id)
ORDER BY a.id_account, c.NUM_WEEK) t1
LEFT JOIN
(SELECT WEEK(t.date_transaction,1) AS NUM_WEEK,
YEAR(t.date_transaction) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(t.date_transaction),WEEK(t.date_transaction,1),' Monday'), '%X%V %W') AS date_start,
t.id_account, SUM(t.amount) AS total
FROM `transaction` t
INNER JOIN account a
ON a.id_account = t.id_account
WHERE t.amount > 0 AND
t.id_account IN (SELECT id_account FROM account WHERE id_customer = 12)
GROUP BY id_account, WEEK(date_transaction,1)) t2
ON t1.NUM_WEEK = t2.NUM_WEEK AND t1.YEAR = t2.YEAR AND t1.id_account = t2.id_account;
Here is SQL Fiddle for that so you can check up result. Hope that is what are you looking for.
Little explanation:
First think i done is that I little modified your first query where you extract data from table calendar and add there one new column called accounts_id. That query now look's like this:
SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK
Please pay attention on this line in SELECT statement
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
Note that when you select for specific customer you need to change customer ID in this line too!!!
Here is Fiddle so you can check result that this query produce.
This is necessary because we need to connect each week with each account to get desired result.
Next step is to extend previous query so we could separate accounts_id column (look result of previous query) so we could get row for each value in that column. Extended query look like this:
SELECT c.NUM_WEEK, c.`YEAR`, c.date_start, a.id_account
FROM (SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK) c
INNER JOIN account a
ON FIND_IN_SET(a.id_account, c.accounts_id)
ORDER BY a.id_account, c.NUM_WEEK
and output you can see in this Fiddle
After that all we need to do is to make left join between this query and query you already wrote in your question (last query).
There might be a better solution or even this one maybe can be improved a little, but I don't have much time now to deal with that and this is the first think that cross my mind...
GL!
P. S. pay attention when you use reserved word in MySQL like YEAR, TRANSACTION etc for column name (as column_name).. that can cause you a treble if have to use them in name of column or table use backquote () to mark them (asyear`)...

MySQL query to determine classes remaining or completed

I have the following data in my webinar_timing table in mysql database
start_time and end_time are of type datetime
id | webinar_id | start_time | end_time
-------------------------------------------------------------------
1 | 5 | 3/18/2015 6:00:00 PM | 3/18/2015 7:00:00 PM
2 | 5 | 3/19/2015 6:00:00 PM | 3/19/2015 7:00:00 PM
3 | 5 | 3/20/2015 6:00:00 PM | 3/20/2015 7:00:00 PM
4 | 5 | 3/21/2015 6:00:00 PM | 3/21/2015 7:00:00 PM
5 | 5 | 3/22/2015 6:00:00 PM | 3/22/2015 7:00:00 PM
6 | 11 | 3/20/2015 8:00:00 PM | 3/20/2015 9:00:00 PM
7 | 11 | 3/21/2015 8:00:00 PM | 3/21/2015 9:00:00 PM
8 | 11 | 3/22/2015 8:00:00 PM | 3/22/2015 9:00:00 PM
9 | 22 | 3/25/2015 8:00:00 PM | 3/25/2015 9:00:00 PM
10 | 22 | 3/27/2015 8:00:00 PM | 3/27/2015 9:00:00 PM
11 | 22 | 3/29/2015 8:00:00 PM | 3/27/2015 9:00:00 PM
Basically, for each webinar, I want the total occurences and number of classes completed or remaining AND the NEXT upcoming class
Egs: When I run this query say at 3/21/2015 at 4:00 PM - this is the result I am expecting
webinar_id | total | Classes Completed | Next Class
----------------------------------------------------------
5 | 5 | 3 | 3/21/2015 6:00:00 PM
11 | 3 | 1 | 3/21/2015 8:00:00 PM
22 | 3 | 0 | 3/25/2015 8:00:00 PM
OR
webinar_id | total | Classes Remaining | Next Class
----------------------------------------------------------
5 | 5 | 2 | 3/21/2015 6:00:00 PM
11 | 3 | 2 | 3/21/2015 8:00:00 PM
22 | 3 | 3 | 3/25/2015 8:00:00 PM
Any help will be appreciated
Thanks in advance
Just use SUM(IF(...))
select webinar_id, count(*) AS total,
SUM(IF(end_time<NOW(), 1, 0)) AS completed,
SUM(IF(start_time>=NOW(), 1, 0)) AS remaining
from webinar_times
group by webinar_id;
You'll have to figure out whether you are looking at start_time or end_time and what to do with equals and little details like that...
SELECT COUNT(*), W.webinar_id, X.COMPLETED, Y.[NOT COMPLETE]
FROM #Webinars W
JOIN (SELECT COUNT(*) AS 'COMPLETED', webinar_id
FROM #Webinars
WHERE end_tim <= '3/18/2015 7:00:00'
GROUP BY webinar_id) X
ON X.webinar_id = W.webinar_id
JOIN (SELECT COUNT(*) AS 'NOT COMPLETE', webinar_id
FROM #Webinars
WHERE end_tim > '3/18/2015 7:00:00'
GROUP BY webinar_id) Y
ON Y.webinar_id = W.webinar_id
GROUP BY W.webinar_id, X.COMPLETED, Y.[NOT COMPLETE]

MySQL delete specified rows from a table when the data from yesterday matches the data from today

I have some data stored in a MySQL table called MyTable like this:
+----------+-----------+---------------------+
| my_id | amount | updated |
+----------+-----------+---------------------+
| 105415 | 81 | 2013-02-13 00:00:00 |
| 105414 | 33 | 2013-02-13 00:00:00 |
| 220801 | 240 | 2013-02-13 00:00:00 |
| 105411 | 118 | 2013-02-13 00:00:00 |
| 105411 | 118 | 2013-02-12 00:00:00 |
| 220801 | 240 | 2013-02-12 00:00:00 |
| 105414 | 33 | 2013-02-11 00:00:00 |
| 105415 | 81 | 2013-02-11 00:00:00 |
+----------+-----------+---------------------+
What I would like to do is delete all the rows from yesterday (2013-02-12) that have the same my_id and amount as today (2013-02-13).
I know how to select all the data from today:
SELECT * FROM 'MyTable' WHERE 'updated' = CURDATE()
I know how to select all the data from yesterday:
SELECT * FROM 'MyTable' WHERE 'updated' = CURDATE()-1
I know the syntax for the DELETE command (DELETE FROM 'MyTable' WHERE...).
How do I delete the rows where the my_id and amount match for yesterday and today?
In the example given, I would want to delete these rows:
| 105411 | 118 | 2013-02-12 00:00:00 |
| 220801 | 240 | 2013-02-12 00:00:00 |
And I would want to keep these rows:
+----------+-----------+---------------------+
| my_id | amount | updated |
+----------+-----------+---------------------+
| 105415 | 81 | 2013-02-13 00:00:00 |
| 105414 | 33 | 2013-02-13 00:00:00 |
| 220801 | 240 | 2013-02-13 00:00:00 |
| 105411 | 118 | 2013-02-13 00:00:00 |
| 105414 | 33 | 2013-02-11 00:00:00 |
| 105415 | 81 | 2013-02-11 00:00:00 |
+----------+-----------+---------------------+
A bit modify from #sgeddes 's answer, I think this a bit more precise to your answer:
Anyways, please give credit as correct answer to #sgeddes 's answer since his answer guided to this:
DELETE t1 FROM MyTable AS t1, MyTable as t2
WHERE t1.updated = CURDATE()-1
AND t2.updated = CURDATE()
AND t2.my_id = t1.my_id
And t2.amount = t1.amount;
If you have a primary key, you can also use this (which is my prefer SQL)
DELETE FROM MyTable
WHERE updated = CURDATE()-1
AND (my_id,amount) in (select my_id,amount
from MyTable
where updated = CURDATE());
Something like this should work:
DELETE M
FROM MyTable M
INNER JOIN MyTable M2 ON
M.My_Id = M2.My_Id AND
M.amount = M2.amount AND
M2.Updated = DATE_ADD(M.Updated, INTERVAL 1 DAY)
Here is the updated Fiddle with your sample data above: http://sqlfiddle.com/#!2/5e288/1
And the Results after the Delete:
MY_ID AMOUNT UPDATED
105415 81 February, 13 2013 00:00:00+0000
105414 33 February, 13 2013 00:00:00+0000
220801 240 February, 13 2013 00:00:00+0000
105411 118 February, 13 2013 00:00:00+0000
105414 33 February, 11 2013 00:00:00+0000
105415 81 February, 11 2013 00:00:00+0000
Good luck.