Get data for specific time range - mysql

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)

Related

MySQL query to select min datetime grouped by 30 day intervals

Here's some dump data..
CREATE TABLE `customer` (
`approve_datetime` datetime DEFAULT NULL,
`created_date` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `customer` (`approve_datetime`, `created_date`)
VALUES
('2015-08-20 04:43:00','2015-08-20'),
(NULL,'2015-09-03'),
('2015-09-17 02:17:00','2015-09-17'),
(NULL,'2015-09-29'),
('2015-09-29 12:44:00','2015-09-29'),
('2015-10-08 03:09:00','2015-10-08'),
('2016-01-20 08:59:00','2016-01-19'),
('2016-05-03 09:38:00','2016-05-02'),
('2016-07-15 11:06:00','2016-07-15'),
(NULL,'2016-08-30'),
('2016-10-18 12:55:00','2016-10-18'),
(NULL,'2017-01-08'),
(NULL,'2017-02-02'),
('2017-02-13 02:58:00','2017-02-13');
Here is my current query which doesn't handle the 30 day groupings correctly.
SELECT a.*
FROM customer a
WHERE a.approve_datetime IN (
SELECT MIN(b.approve_datetime)
FROM customer b
WHERE b.created_date BETWEEN a.created_date
AND DATE_ADD(a.created_date, INTERVAL 30 DAY)
)
Which gives me the following.
+---------------------+--------------+
| approve_datetime | created_date |
+---------------------+--------------+
| 2015-08-20 04:43:00 | 2015-08-20 |
| 2015-09-17 02:17:00 | 2015-09-17 |
| 2015-09-29 12:44:00 | 2015-09-29 |
| 2015-10-08 03:09:00 | 2015-10-08 |
| 2016-01-20 08:59:00 | 2016-01-19 |
| 2016-05-03 09:38:00 | 2016-05-02 |
| 2016-07-15 11:06:00 | 2016-07-15 |
| 2016-10-18 12:55:00 | 2016-10-18 |
| 2017-02-13 02:58:00 | 2017-02-13 |
+---------------------+--------------+
Can the query be altered to achieve the following results?
+---------------------+--------------+
| approve_datetime | created_date |
+---------------------+--------------+
| 2015-08-20 04:43:00 | 2015-08-20 |
| 2015-09-29 12:44:00 | 2015-09-29 |
| 2016-01-20 08:59:00 | 2016-01-19 |
| 2016-05-03 09:38:00 | 2016-05-02 |
| 2016-07-15 11:06:00 | 2016-07-15 |
| 2016-10-18 12:55:00 | 2016-10-18 |
| 2017-02-13 02:58:00 | 2017-02-13 |
+---------------------+--------------+
Notice that records with created_date's 2015-09-17 and 2015-10-08 have been removed because they are within 30 days of the previous record which is the minimum date for that particular group. 2015-08-20 + 30 days starts off the first group with 2015-08-20 being the min date for that group.
I hope what I'm trying to achieve makes sense.
take a look at this. the result is different but look if this correct. Column 3 and 4 are only to see how it works.
SELECT
min(b.approve_datetime) AS approve_datetime
, min(b.created_date) AS created_date
, DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 AS dayd30
, FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 ) AS dayd30floorint
FROM customer b
GROUP BY FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 )
ORDER BY b.created_date ;
sample
MariaDB [testdb]> SELECT
-> min(b.approve_datetime) AS approve_datetime
-> , min(b.created_date) AS created_date
-> , DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 AS dayd30
-> , FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 ) AS dayd30floorint
-> FROM customer b
-> GROUP BY FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 )
-> ORDER BY b.created_date ;
+---------------------+--------------+---------+----------------+
| approve_datetime | created_date | dayd30 | dayd30floorint |
+---------------------+--------------+---------+----------------+
| 2015-08-20 04:43:00 | 2015-08-20 | 0.0000 | 0 |
| 2015-09-29 12:44:00 | 2015-09-29 | 1.3333 | 1 |
| 2016-01-20 08:59:00 | 2016-01-19 | 5.0667 | 5 |
| 2016-05-03 09:38:00 | 2016-05-02 | 8.5333 | 8 |
| 2016-07-15 11:06:00 | 2016-07-15 | 11.0000 | 11 |
| NULL | 2016-08-30 | 12.5333 | 12 |
| 2016-10-18 12:55:00 | 2016-10-18 | 14.1667 | 14 |
| NULL | 2017-01-08 | 16.9000 | 16 |
| NULL | 2017-02-02 | 17.7333 | 17 |
| 2017-02-13 02:58:00 | 2017-02-13 | 18.1000 | 18 |
+---------------------+--------------+---------+----------------+
10 rows in set (0.00 sec)
MariaDB [testdb]>

MySQL: multiple count in one row

I have next data:
mysql> select no,crt_date,tobilling_date,sent_to_client,dop_prov from assistfin limit 20;
+--------+---------------------+---------------------+----------------+------------+
| no | crt_date | tobilling_date | sent_to_client | dop_prov |
+--------+---------------------+---------------------+----------------+------------+
| 50.01 | 2014-02-05 10:28:10 | 2014-02-05 14:42:35 | 2014-04-16 | 2014-09-23 |
| 123.01 | 2014-02-05 19:17:36 | 2014-03-17 18:58:05 | 2014-04-10 | 2014-06-30 |
| 51.01 | 2014-02-06 00:09:32 | 2014-03-20 16:53:46 | 2014-04-10 | 2014-06-30 |
| 124.01 | 2014-02-06 15:29:08 | 2014-03-20 17:04:42 | 2014-04-10 | 2014-06-30 |
| 230.01 | 2014-02-07 22:01:11 | 2014-03-20 16:41:03 | 2014-04-10 | 2014-06-30 |
| 252.01 | 2014-02-08 02:52:33 | 2014-03-20 16:43:03 | 2014-04-10 | 2014-06-30 |
| 123.02 | 2014-02-08 03:00:52 | 2014-03-17 18:58:10 | 2014-04-10 | 2014-06-30 |
| 213.01 | 2014-02-08 04:01:35 | 2014-03-26 19:03:01 | 2014-04-10 | 2014-09-19 |
| 55.01 | 2014-02-08 21:04:45 | 2014-03-07 18:40:46 | NULL | 2014-06-26 |
| 126.01 | 2014-02-08 21:46:58 | 2014-09-02 18:39:36 | 2014-09-09 | 2014-09-26 |
| 284.01 | 2014-02-09 01:52:54 | 2014-06-11 19:11:06 | 2014-07-02 | 2014-07-21 |
| 261.01 | 2014-02-09 02:20:34 | 2014-03-17 20:57:39 | 2014-04-10 | 2014-06-30 |
| 318.01 | 2014-02-09 03:09:28 | 2014-03-17 20:44:25 | 2014-04-10 | 2014-06-30 |
| 225.01 | 2015-02-10 03:21:08 | 2014-03-20 16:57:56 | 2014-04-10 | 2014-06-30 |
| 248.01 | 2014-02-09 03:30:58 | 2014-03-18 18:02:21 | 2014-04-10 | 2014-06-30 |
| 178.01 | 2014-04-05 03:35:25 | 2014-03-21 17:10:12 | 2014-04-10 | 2014-06-30 |
| 184.01 | 2014-04-08 04:01:13 | 2015-03-20 16:38:02 | 2015-04-10 | 2015-06-30 |
| 320.01 | 2014-04-08 05:57:23 | 2015-03-17 20:49:19 | 2015-04-10 | 2015-06-30 |
| 230.02 | 2015-05-08 06:18:15 | 2016-03-20 16:41:08 | 2016-04-10 | 2016-06-06 |
| 325.01 | 2014-05-09 06:23:50 | 2015-03-17 20:42:04 | 2015-04-10 | 2015-06-30 |
+--------+---------------------+---------------------+----------------+------------+
Need to get next data:
+---------+---------+--------+-----------+---------+
| year | Created | Passed | To client | To prov |
+---------+---------+--------+-----------+---------+
| 2016-01 | 1901 | 1879 | 1873 | 1743 |
| 2016-02 | 2192 | 2169 | 2114 | 1912 |
| 2016-03 | 2693 | 2639 | 2539 | 2309 |
| 2016-04 | 2634 | 2574 | 2273 | 1976 |
| 2016-05 | 2593 | 2497 | 1109 | 949 |
| 2016-06 | 471 | 449 | 2 | 78 |
+---------+---------+--------+-----------+---------+
Where year like DATE_FORMAT(curdate(), '%Y-%m'), next column Count(assistfin.crt_date) as Created.
The problem is that crt_date can be like 2015%, but sent_to_client or dop_prov can be like 2016%.
How to make correct query?
Ok sorry this is so long and messy and also I couldnt do it using unions as I so arrogantly posted in the comments, also have to reference MySQL: Is it possible to 'fill' a SELECT with values without a table? that gave me the list of months. You could rewrite it so you left join all the tables to crt_date, but then it wont show a month when nothing was created, hence the generated months table. The original query had a limit 120 in the months, but I have replaced it with a datetime > '2014' for you to change with your earliest date.
Try this and see how quickly it runs for you.
select Months.yearmonth, created, passed, to_client, to_prov
from
(SELECT date_format(datetime,'%Y-%m') as yearmonth
FROM (
select (curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) MONTH) as datetime
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) as a
cross join (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) as b
cross join (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) as c
) AS t
where datetime > '2014' -- enter your earliest year here
ORDER BY datetime ASC) Months left join
(select date_format(crt_date,'%Y-%m') as yearmonth, count(no) as "created" from assistfin group by yearmonth) created on Months.yearmonth=created.yearmonth
left join
(select date_format(tobilling_date,'%Y-%m') as yearmonth, count(no) as "passed" from assistfin group by yearmonth) passed on Months.yearmonth=passed.yearmonth
left join
(select date_format(sent_to_client,'%Y-%m') as yearmonth, count(no) as "to_client" from assistfin group by yearmonth) to_client on Months.yearmonth=to_client.yearmonth
left join
(select date_format(dop_prov,'%Y-%m') as yearmonth, count(no) as "to_prov" from assistfin group by yearmonth) to_prov on Months.yearmonth=to_prov.yearmonth
where
group by yearmonth;
Use group by and date_forma in where
select date_format(crt_date, '%Y-%m') as year, count(sent_to_client ), count(dop_pprov)
from assistfin
where date_format(crt_date, '%Y-%m') = date_format(now(), '%Y-%m')
group by year
for the year you can
select date_format(crt_date, '%Y-%m') as year, count(sent_to_client ), count(dop_pprov)
from assistfin
where date_format(crt_date, '%Y') = date_format(now(), '%Y')
group by year
OR for A Range OF yearS you can
select date_format(crt_date, '%Y-%m') as year, count(sent_to_client ), count(dop_pprov)
from assistfin
where date_format(crt_date, '%Y')
BETWEEN(date_format(now(),'%Y')-2) and date_format(now(), '%Y')
group by year

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)

select timestamp values between time durations where a column has 0 in MySQL

I want to select the time limits(stamp_date) when the uptime has 0 or continues to be in 0.
TABLE:
CREATE TABLE IF NOT EXISTS sample (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
sname VARCHAR(30) NULL,
uptime BIGINT,
stamp_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
INSERT statements:
insert into sample values(null,'hi',10,'2015-01-08 05:30:00');
insert into sample values(null,'hi',20,'2015-01-08 05:40:00');
insert into sample values(null,'hi',30,'2015-01-08 05:50:00');
insert into sample values(null,'hi',40,'2015-01-08 06:00:00');
insert into sample values(null,'hi',50,'2015-01-08 06:10:00');
insert into sample values(null,'hi',0,'2015-01-08 06:20:00');
insert into sample values(null,'hi',10,'2015-01-08 06:30:00');
insert into sample values(null,'hi',20,'2015-01-08 06:40:00');
insert into sample values(null,'hi',30,'2015-01-08 06:50:00');
insert into sample values(null,'hi',40,'2015-01-08 07:00:00');
insert into sample values(null,'hi',0,'2015-01-08 07:10:00');
insert into sample values(null,'hi',0,'2015-01-08 07:20:00');
insert into sample values(null,'hi',0,'2015-01-08 07:30:00');
insert into sample values(null,'hi',0,'2015-01-08 07:40:00');
insert into sample values(null,'hi',0,'2015-01-08 07:50:00');
insert into sample values(null,'hi',10,'2015-01-08 08:00:00');
insert into sample values(null,'hi',20,'2015-01-08 08:10:00');
insert into sample values(null,'hi',0,'2015-01-08 08:20:00');
insert into sample values(null,'hi',40,'2015-01-08 08:30:00');
sample table:
mysql> select * from sample;
+----+-------+-------+---------------------+
| id | sname | uptime| stamp_date |
+----+-------+-------+---------------------+
| 1 | hi | 10 | 2015-01-08 05:30:00 |
| 2 | hi | 20 | 2015-01-08 05:40:00 |
| 3 | hi | 30 | 2015-01-08 05:50:00 |
| 4 | hi | 40 | 2015-01-08 06:00:00 |
| 5 | hi | 50 | 2015-01-08 06:10:00 |
| 6 | hi | 0 | 2015-01-08 06:20:00 |
| 7 | hi | 10 | 2015-01-08 06:30:00 |
| 8 | hi | 20 | 2015-01-08 06:40:00 |
| 9 | hi | 30 | 2015-01-08 06:50:00 |
| 10 | hi | 40 | 2015-01-08 07:00:00 |
| 11 | hi | 0 | 2015-01-08 07:10:00 |
| 12 | hi | 0 | 2015-01-08 07:20:00 |
| 13 | hi | 0 | 2015-01-08 07:30:00 |
| 14 | hi | 0 | 2015-01-08 07:40:00 |
| 15 | hi | 0 | 2015-01-08 07:50:00 |
| 16 | hi | 10 | 2015-01-08 08:00:00 |
| 17 | hi | 20 | 2015-01-08 08:10:00 |
| 18 | hi | 0 | 2015-01-08 08:20:00 |
| 19 | hi | 40 | 2015-01-08 08:30:00 |
+----+-------+-------+---------------------+
19 rows in set (0.00 sec)
1) The link was down (uptime=0) between 06:20:00 to 06:30:00
2) The link was down (uptime=0) between 07:10:00 to 08:00:00
3) The link was down (uptime=0) between 08:20:00 to 08:30:00
Expected result should be like the below:
+++++++++++++++++++++++++
| When Uptime is 0 |
+++++++++++++++++++++++++
| 06:20:00 to 06:30:00 |
| 07:10:00 to 08:00:00 |
| 08:20:00 to 08:30:00 |
+++++++++++++++++++++++++
Could someone please help me to write a SQL or stored procedure to achieve the above result?
Thanks,
Yogesh
If your IDs have no holes in them (e.g. 18 is not followed by 20), then the following query will do the trick:
select concat(time(r.stamp_date), ' to ',
IFNULL((select time(min(stamp_date))
from sample
where id > r.id and uptime != 0
), "NOW")) `When Uptime is 0`
from sample l
join
sample r
on l.id = r.id - 1
where l.uptime != 0 and r.uptime = 0;
This is what it returns for your data with an extra downtime entry at the end
+----------------------+
| When Uptime is 0 |
+----------------------+
| 06:20:00 to 06:30:00 |
| 07:10:00 to 08:00:00 |
| 08:20:00 to 08:30:00 |
| 08:40:00 to NOW |
+----------------------+
4 rows in set (0.00 sec)
If your IDs do have holes, then you'll need to modify the ON condition a little bit
select concat(time(r.stamp_date), ' to ',
IFNULL((select time(min(stamp_date))
from sample
where id > r.id and uptime != 0
), "NOW")) `When Uptime is 0`
from sample l
join
sample r
on l.id = (select max(id) from sample where id < r.id)
where l.uptime != 0 and r.uptime = 0;
check this out on fiddle here is fiddle
SELECT
CONCAT(
DATE_FORMAT(a.stamp_date, '%H:%i:%s'),
' to ',
DATE_FORMAT(b.stamp_date, '%H:%i:%s')
) AS 'When Uptime is 0'
FROM
(SELECT
id,
stamp_date
FROM
sample
WHERE uptime = 0) AS a,
(SELECT
id,
stamp_date
FROM
sample
WHERE uptime <> 0) AS b
WHERE a.stamp_date < b.stamp_date
AND a.id = b.id-1
GROUP BY a.id

sql query to add rows based on a time difference

i have a table that has the following columns : s.no,house_no,energy,time
i want to find the total energy for each house for every one hour.
table :
+-----+----------+---------------------+--------+
| sno | house_no | time | energy |
+-----+----------+---------------------+--------+
| 1 | 1 | 2014-10-20 10:00:00 | 5 |
| 2 | 1 | 2014-10-20 10:30:00 | 10 |
| 3 | 2 | 2014-10-20 10:00:00 | 7 |
| 4 | 1 | 2014-10-20 11:01:00 | 3 |
| 5 | 2 | 2014-10-20 11:00:00 | 20 |
+-----+----------+---------------------+--------+
i am trying for 10-11 am.But this query sums the energy of the rows whose time value is greater than 11 am also.
SELECT house_no, sum( energy ) AS sum, time
FROM main
GROUP BY house_no
HAVING (
TIMESTAMPDIFF(
MINUTE , time, '2014-10-20 11:00:00' ) >0)
the result is :
+----------+------+---------------------+
| house_no | sum | time |
+----------+------+---------------------+
| 1 | 18 | 2014-10-20 10:00:00 |
| 2 | 27 | 2014-10-20 10:00:00 |
+----------+------+---------------------+
but the actual answer should be:
+----------+------+---------------------+
| house_no | sum | time |
+----------+------+---------------------+
| 1 | 15 | 2014-10-20 10:00:00 |
| 2 | 7 | 2014-10-20 10:00:00 |
+----------+------+---------------------+
You have to group the time also based on the hours
SELECT house_no, sum( energy ) AS sum, time
FROM main
GROUP BY house_no,DATE_FORMAT(time,'%d %b %Y %H')
HAVING (
TIMESTAMPDIFF(
MINUTE , time, '2014-10-20 11:00:00' ) >0)
DEMO