MySQL Dynamic assignment of month based on current date - mysql
Hope you are doing well..I am trying to convert a plan table as below
Input
Segment | Model |FC1 |FC2 |FC3 |FC4 |FC5 | FC6 | FC7 | FC8 | FC9 | FC10 | FC11 | FC12
HRX P3412 9 14 11 22 17 23 18 15 23 12 12 19
SRX O321 11 8 8 9 9 16 19 7 22 12 11 15
SRX LD12 14 10 20 22 18 19 10 17 21 16 10 21
HRX M421 17 18 16 12 14 17 10 16 8 8 7 23
MRX N342 3 23 16 13 20 9 16 14 16 17 10 11
HRX J231 4 10 20 20 21 23 17 22 14 15 8 22
into the table below based on the current date and the reference table
Segment |Model| Apr-22 |May-22 |Jun-22 |Jul-22 |Aug-22 |Sep-22|Oct-22|Nov-22 | Dec-22 | Jan-23 |Feb-23 |Mar-23
HRX P3412 9 14 11 22 17 23 18 15 23 12 12 19
SRX O321 11 8 8 9 9 16 19 7 22 12 11 15
SRX LD12 14 10 20 22 18 19 10 17 21 16 10 21
HRX M421 17 18 16 12 14 17 10 16 8 8 7 23
MRX N342 3 23 16 13 20 9 16 14 16 17 10 11
HRX J231 4 10 20 20 21 23 17 22 14 15 8 22
Reference table:
Fiscal Month From to
Jan-22 Dec 26 2021 Jan 22 2022
Feb-22 Jan 23 2022 19-Feb-22
Mar-22 20-Feb-22 26-Mar-22
Apr-22 27-Mar-22 23-Apr-22
May-22 24-Apr-22 21-May-22
Jun-22 22-May-22 25-Jun-22
Jul-22 26-Jun-22 23-Jul-22
Aug-22 24-Jul-22 20-Aug-22
Sep-22 21-Aug-22 24-Sep-22
Oct-22 25-Sep-22 22-Oct-22
Nov-22 23-Oct-22 19-Nov-22
Dec-22 20-Nov-22 31-Dec-22
So I need to basically map the column names (FC1,FC2,FC3...input table) to fiscal month based on the current date and looking up the reference table for the fiscal month... Can you please help me here..
The column names should change every fiscal month according to the reference table dynamically ..For example FC1 should be renamed to May 2022 and FC2 should be renamed to June 2022 from 24th April 2022...Similarly from 22nd may 2022 FC1 should be renamed to June 2022, FC2 should be renamed to July 2022...
Please find the DDL for the tables:
create table input
(segment varchar(40),
model varchar (40),
FC1 int,
FC2 int,
FC3 int,
FC4 int,
FC5 int,
FC6 int,
FC7 int,
FC8 int,
FC9 int,
FC10 int,
FC11 int,
FC12 int)
insert into input values
('HRX','P3412','9','14','11','22','17','23','18','15','23','12','12','19'),
('SRX','O321','11','8','8','9','9','16','19','7','22','12','11','15'),
('SRX','LD12','14','10','20','22','18','19','10','17','21','16','10','21'),
('HRX','M421','17','18','16','12','14','17','10','16','8','8','7','23'),
('MRX','N342','3','23','16','13','20','9','16','14','16','17','10','11'),
('HRX','J231','4','10','20','20','21','23','17','22','14','15','8','22')
create table output
(segment varchar(40),
model varchar(40),
Apr2022 int,
May2022 int,
Jun2022 int,
jul2022 int,
aug2022 int,
sep2022 int,
oct2022 int,
nov2022 int,
dec2022 int,
Jan2023 int,
feb2023 int,
mar2023 int)
insert into output values
('HRX','P3412','9','14','11','22','17','23','18','15','23','12','12','19'),
('SRX','O321','11','8','8','9','9','16','19','7','22','12','11','15'),
('SRX','LD12','14','10','20','22','18','19','10','17','21','16','10','21'),
('HRX','M421','17','18','16','12','14','17','10','16','8','8','7','23'),
('MRX','N342','3','23','16','13','20','9','16','14','16','17','10','11'),
('HRX','J231','4','10','20','20','21','23','17','22','14','15','8','22')
create table reference
(fiscalmonth varchar(40),
from date,
to date
)
insert into reference values
('Jan 2022','Dec 26 2021 ','Jan 22 2022'),
('Feb 2022','Jan 23 2022','Feb 19 2022'),
('March 2022','feb 20 2022','Mar 26 2022'),
('April 2022','Mar 27 2022','Apr 23 2022'),
('May 2022','Apr 24 2022','May 21 2022'),
('June 2022','May 22 2022','Jun 25 2022'),
('July 2022','June 26 2022','Jul 23 2022'),
('Aug 2022','Jul 24 2022','Aug 20 2022'),
('Sep 2022','Aug 21 2022','Sep 24 2022'),
('Oct 2022','Sep 25 2022','Oct 22 2022'),
('Nov 2022','Oct 23 2022','Nov 19 2022'),
('Dec 2022','Nov 20 2022','Dec 31 2022')
We can fetch the first 12 rows starting with the current month, and number them using row_number. We then do a manual pivot, using rn so that it will not need changing from month to month.
The only thing that will need to be kept up to date is the references table. (I have added some months for 2023 using the same dates as 2022.
select
'' segment,
'' model,
max(case when rn = 1 then fiscalmonth end) FC1,
max(case when rn = 2 then fiscalmonth end) FC2,
max(case when rn = 3 then fiscalmonth end) FC3,
max(case when rn = 4 then fiscalmonth end) FC4,
max(case when rn = 5 then fiscalmonth end) FC5,
max(case when rn = 6 then fiscalmonth end) FC6,
max(case when rn = 7 then fiscalmonth end) FC7,
max(case when rn = 8 then fiscalmonth end) FC8,
max(case when rn = 9 then fiscalmonth end) FC9,
max(case when rn = 10 then fiscalmonth end) FC10,
max(case when rn = 11 then fiscalmonth end) FC11,
max(case when rn = 12 then fiscalmonth end) FC12
from
(select
row_number() over (order by to_ ) as rn,
fiscalmonth from reference
where to_ >= curdate()
limit 12) as months
union all
select * from input
segment | model | FC1 | FC2 | FC3 | FC4 | FC5 | FC6 | FC7 | FC8 | FC9 | FC10 | FC11 | FC12
:------ | :---- | :--------- | :------- | :-------- | :-------- | :------- | :------- | :------- | :------- | :------- | :------- | :------- | :---------
| | April 2022 | May 2022 | June 2022 | July 2022 | Aug 2022 | Sep 2022 | Oct 2022 | Nov 2022 | Dec 2022 | Jan 2023 | Feb 2023 | March 2023
HRX | P3412 | 9 | 14 | 11 | 22 | 17 | 23 | 18 | 15 | 23 | 12 | 12 | 19
SRX | O321 | 11 | 8 | 8 | 9 | 9 | 16 | 19 | 7 | 22 | 12 | 11 | 15
SRX | LD12 | 14 | 10 | 20 | 22 | 18 | 19 | 10 | 17 | 21 | 16 | 10 | 21
HRX | M421 | 17 | 18 | 16 | 12 | 14 | 17 | 10 | 16 | 8 | 8 | 7 | 23
MRX | N342 | 3 | 23 | 16 | 13 | 20 | 9 | 16 | 14 | 16 | 17 | 10 | 11
HRX | J231 | 4 | 10 | 20 | 20 | 21 | 23 | 17 | 22 | 14 | 15 | 8 | 22
db<>fiddle here
Related
Normalize data with no matter exist or no exist into single SQL query
I have this record in my table TblFinishByClass. Some ID does not attend the Class thus there will have no record exist. There is only 3 class available which are C, TP, and TT. ID Class Month Year Finished Total ASAN014 C 04 2020 12 19 ASAN014 TP 04 2020 4 6 ASAN014 TT 04 2020 2 7 ASAN014 C 05 2020 10 18 ASAN014 TP 05 2020 1 2 ASAN014 TT 05 2020 2 6 ASAN015 C 04 2020 21 24 ASAN015 TP 04 2020 0 1 ASAN015 TT 04 2020 8 11 ASAN015 C 05 2020 14 19 ASAN015 TT 05 2020 4 5 As mention early. If ASAN015 does not attend the class for TT, it's data default should be zero for FinishedTT and TotalTT. I need to group it by ID, Month, and Year in which it will look like the following table: ID Month Year FinishedC TotalC FinishedTP TotalTP FinishedTT TotalTT ASAN014 04 2020 12 19 4 6 2 7 ASAN014 05 2020 10 18 1 2 2 6 ASAN015 04 2020 21 24 0 1 8 11 ASAN015 05 2020 14 19 4 5 0 0 My question is could we do this in one query?
You can use conditional aggregation. SELECT ID, Month, Year, SUM(CASE WHEN Class = 'C' THEN Finished ELSE 0 END) AS FinishedC, SUM(CASE WHEN Class = 'C' THEN Total ELSE 0 END) AS TotalC, SUM(CASE WHEN Class = 'TT' THEN Finished ELSE 0 END) AS FinishedTT, SUM(CASE WHEN Class = 'TT' THEN Total ELSE 0 END) AS TotalTT, SUM(CASE WHEN Class = 'TP' THEN Finished ELSE 0 END) AS FinishedTP, SUM(CASE WHEN Class = 'TP' THEN Total ELSE 0 END) AS TotalTP FROM TblFinishByClass GROUP BY ID, Month, Year; Results: +----+---------+-------+------+-----------+--------+------------+---------+------------+---------+ | | ID | Month | Year | FinishedC | TotalC | FinishedTT | TotalTT | FinishedTP | TotalTP | +----+---------+-------+------+-----------+--------+------------+---------+------------+---------+ | 1 | ASAN014 | 4 | 2020 | 12 | 19 | 2 | 7 | 4 | 6 | | 2 | ASAN014 | 5 | 2020 | 10 | 18 | 2 | 6 | 1 | 2 | | 3 | ASAN015 | 4 | 2020 | 21 | 24 | 8 | 11 | 0 | 1 | | 4 | ASAN015 | 5 | 2020 | 14 | 19 | 4 | 5 | 0 | 0 | +----+---------+-------+------+-----------+--------+------------+---------+------------+---------+
Get single unique row from duplicate data with multiple tables in mysql
I want to get the unique data from multiple tables with the highest id Refer below data Users Table id firstname_english ------ -------------------- 2 Lama 4 Akram 6 Ammar 8 Basil 10 Sami 12 Hasan 14 Adnan 16 Mamoon 18 Sulaiman 20 Wasfi 22 Mervat Users form status with their id id users_id status_id ------ ----------- ----------- 3 2 10 368 4 10 5 4 10 402 6 9 7 6 10 9 8 10 11 10 10 223 10 10 13 12 10 3253 14 2 15 14 10 17 16 10 1488 16 9 231 16 10 19 18 10 22 20 10 750 20 9 232 22 10 24 22 10 2935 22 9 297 22 10 The Result I need id firstname_english status_id form_id ------ -------------------- -------------------- 2 Lama 10 3 4 Akram 10 368 6 Ammar 9 402 8 Basil 10 8 10 Sami 10 223 12 Hasan 10 12 ........and so on I need to display the highest data from the table 2 with the matching id of table 1
For MySql 8.0+ use row_number() window function: select u.id, u.firstname_english, f.status_id, f.id form_id from users u inner join ( select *, row_number() over (partition by users_id order by id desc) rn from users_form ) f on f.users_id = u.id where f.rn = 1 See the demo. For previous versions of MySql: select u.id, u.firstname_english, f.status_id, f.id form_id from users u inner join ( select uf.* from users_form uf where not exists ( select 1 from users_form where users_id = uf.users_id and id > uf.id ) ) f on f.users_id = u.id See the demo. Results: | id | firstname_english | status_id | form_id | | --- | ----------------- | --------- | ------- | | 2 | Lama | 10 | 3 | | 4 | Akram | 10 | 368 | | 6 | Ammar | 9 | 402 | | 8 | Basil | 10 | 9 | | 10 | Sami | 10 | 223 | | 12 | Hasan | 10 | 13 | | 14 | Adnan | 2 | 3253 | | 16 | Mamoon | 9 | 1488 | | 18 | Sulaiman | 10 | 19 | | 20 | Wasfi | 9 | 750 | | 22 | Mervat | 9 | 2935 |
How do I calculate the hourly 4 week moving average by weekday?
Given a table with a datetime column, I want to get the 4 week moving average number of entries per hour with the day of week for each result. So for instance, between Oct 1st and Oct 13th, I'd like to get back a result that shows the 4 week rolling average for number of rows grouped by hour and dayofweek. What I have so far gets me the 4 week hourly totals, but not rolling totals: SELECT DAYOFWEEK(start_time) as DOW, date_format( start_time, '%H' ) as 'HOUR', count( * ) as 'count' FROM mytable WHERE start_time >='2017-08-01' and start_time <= '2017-08-29' GROUP BY DAYOFWEEK(start_time),date_format( start_time, '%H' )
Here is a partially tested approach. It uses date parameters to ensure consistency of the where clauses. Other parameters are also used to control the hourly bucket (I used 3 in limited testing), and the number of weeks (I used 0 in testing as I had a very small set of rows). The first subquery is used to produce "ranges" which when joined to the source rows will place those rows into each "rolling n hourly range". Those ranges are defined by using a date_format output YYYYMMDDHH which are strings, and then the data is also forced to this same string format for joining, so if being used on a large table this may cause performance issues (yes, not sargable, I don't like it either). This solution may be seen working here at SQL Fiddle Schema Setup: CREATE TABLE `myTable` ( `id` mediumint(8) unsigned NOT NULL auto_increment, `start_time` datetime, PRIMARY KEY (`id`) ) AUTO_INCREMENT=1; INSERT INTO MyTable (`start_time`) VALUES ('2017-08-01 00:01:00'), ('2017-08-01 00:15:00'), ('2017-08-01 00:29:00'), ## more here, 3 rows per hour over a narrow date range ('2017-08-03 08:01:00'), ('2017-08-03 08:15:00'), ('2017-08-03 08:29:00') ; Query set #start_time := '2017-08-02'; set #num_hrs := 4; -- controls length of rolling period e.g. 4 hours each set #num_weeks := 4; -- controls the date date set #end_time := date_add(#start_time, INTERVAL ((7 * #num_weeks)+1) DAY); SELECT DOW , hour_of_day , COUNT(*) period_count , (COUNT(*) * 1.0) / #num_hrs rolling_av FROM ( ## build a set of ranges in YYYYMMDDHH format differing by the wanted number of hours SELECT id , DATE_FORMAT(date_add(start_time, INTERVAL (#num_hrs*-1) HOUR), '%Y%m%d%H') as range_start , DATE_FORMAT(start_time, '%Y%m%d%H') as range_end FROM mytable WHERE start_time >= #start_time and start_time < #end_time ) R INNER JOIN ( SELECT start_time , DAYOFWEEK(start_time) as DOW , date_format(start_time, '%H' ) as hour_of_day FROM MyTable WHERE start_time >= #start_time and start_time < #end_time ) T ON DATE_FORMAT(T.start_time, '%Y%m%d%H') >= R.range_start AND DATE_FORMAT(T.start_time, '%Y%m%d%H') <= R.range_end GROUP BY DOW, hour_of_day ORDER BY DOW, hour_of_day ; Results: | DOW | hour_of_day | period_count | rolling_av | |-----|-------------|--------------|------------| | 4 | 00 | 36 | 12 | | 4 | 01 | 36 | 12 | | 4 | 02 | 36 | 12 | | 4 | 03 | 36 | 12 | | 4 | 04 | 36 | 12 | | 4 | 05 | 36 | 12 | | 4 | 06 | 36 | 12 | | 4 | 07 | 36 | 12 | | 4 | 08 | 36 | 12 | | 4 | 09 | 36 | 12 | | 4 | 10 | 36 | 12 | | 4 | 11 | 36 | 12 | | 4 | 12 | 36 | 12 | | 4 | 13 | 36 | 12 | | 4 | 14 | 36 | 12 | | 4 | 15 | 36 | 12 | | 4 | 16 | 36 | 12 | | 4 | 17 | 36 | 12 | | 4 | 18 | 36 | 12 | | 4 | 19 | 36 | 12 | | 4 | 20 | 36 | 12 | | 4 | 21 | 27 | 9 | | 4 | 22 | 18 | 6 | | 4 | 23 | 9 | 3 |
SQL sub queries - one alias column
course_completions +-----------------------------------------------+ | id coursemodid userid state timemodified | +-----------------------------------------------+ | 370 23 2 1 1433582890 | | 329 24 89 1 1427771915 | | 333 30 39 1 1428309816 | | 332 32 39 1 1428303307 | | 327 33 40 1 1427689703 | | 328 34 89 1 1427710711 | | 303 35 41 1 1410258482 | | 358 36 99 1 1432020067 | | 365 25 2 1 1433142455 | | 304 26 69 1 1410717866 | | 353 37 95 1 1430387005 | | 416 38 2 1 1438972465 | | 300 27 70 1 1409824001 | | 302 29 74 1 1412055704 | | 297 30 2 1 1409582123 | | 301 133 41 1 1410255923 | | 336 133 91 1 1428398435 | | 364 133 40 1 1433142348 | | 312 133 85 1 1425863621 | +-----------------------------------------------+ course_modules +------------------+ | id course | +------------------+ | 23 6 | | 24 6 | | 25 6 | | 26 6 | | 27 6 | | 28 6 | | 29 8 | | 30 8 | | 31 8 | | 32 8 | | 33 8 | | 34 5 | | 35 5 | | 36 5 | | 37 5 | | 38 5 | | 39 9 | | 40 9 | | 41 9 | +------------------+ course_mod_settings +--------------------------------------+ |id course modinstance | +--------------------------------------+ | 27 8 30 | | 28 8 31 | | 29 8 32 | | 30 8 33 | | 31 6 23 | | 32 6 24 | | 33 6 25 | | 34 6 26 | | 35 6 27 | | 36 6 28 | | 37 9 39 | | 38 9 40 | | 39 9 41 | +--------------------------------------+ I was trying about to frame two sub queries in one SQL statement like I want the count of 'criteria mod settings' table values in one column and count of 'course_completions' table values in one column for a particular user along with course. There shouldn't be relation between count(cms.id) and count(cc.id) except course id, because count(cms.id) is the count of user modules and count(cc.id) is the settings count set by default. OUTPUT: COURSE USERID count(cms.id) count(cc.id) 6 89 3 6 6 39 7 6 6 40 5 6 8 69 3 4 8 2 0 4 8 95 4 4 COURSE : getting courseid USERID : getting userid count(cms.id) : getting the count of user completed modules. count(cc.id) : getting the count of settings (ex: For course 6, settings count has 6 and for course 4, settings count has 3. SELECT cm.course ,cc.userid ,count(cc.coursemodid) AS usermodules ,( SELECT count(ccc.id) FROM course_mod_settings cms INNER JOIN course_modules cm ON cms.course = cm.course ) AS modsettings FROM course_completions cc INNER JOIN course_modules cm ON cc.coursemodid = cm.id WHERE cc.STATE = 1 GROUP BY cm.cours ,cc.userid
I have read your comment above. Have you tried something like this? I didn't test the query, it's just a thought. I might be wrong. SELECT cms.course AS COURSE, cc.userid AS USERID, COUNT(cms.id), COUNT(cc.id) FROM course_completions AS cc INNER JOIN course_modules AS cm ON cc.coursemodid = cm.id INNER JOIN course_mod_settings AS cms cm.course = cms.course WHERE cc.state = 1 GROUP BY cm.course, cc.userid
Mysql - sql query to get next class based on date
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)