I am working on MySQL. I have a table in which there are some records. Below is my table
CREATE TABLE `mdc_meters_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`msn` varchar(100) DEFAULT NULL,
`kwh_t` varchar(100) DEFAULT NULL,
`data_date_time` datetime DEFAULT NULL,
`s_type` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=52702 DEFAULT CHARSET=latin1;
/*Data for the table `mdc_meters_data` */
insert into `mdc_meters_data`(`id`,`msn`,`kwh_t`,`data_date_time`,`s_type`) values(49641,'4A60193390662','2068.3','2020-11-01 00:02:17','WAPDA'),
(49642,'00209701','1476.59','2020-11-01 00:02:47','Sync Meter'),(49643,'00209702','1389.79','2020-11-01 00:03:17','Sync Meter'),(49644,'4A60193390662','2068.3','2020-11-01 00:04:57','WAPDA'),(49645,'00209701','1476.6','2020-11-01 00:05:28','Sync Meter'),(49646,'00209702','1389.81','2020-11-01 00:05:58','Sync Meter'),(49647,'4A60193390662','2068.3','2020-11-01 00:07:38','WAPDA'),(49648,'00209701','1476.6','2020-11-01 00:08:08','Sync Meter'),(49649,'00209702','1389.81','2020-11-01 00:08:38','Sync Meter'),(49650,'4A60193390662','2068.3','2020-11-01 00:10:19','WAPDA'),(49651,'00209701','1476.6','2020-11-01 00:10:49','Sync Meter'),(49652,'00209702','1389.82','2020-11-01 00:11:19','Sync Meter'),(49653,'4A60193390662','2068.3','2020-11-01 00:12:59','Generator'),(49654,'00209701','1476.61','2020-11-01 00:13:30','Sync Meter'),(49655,'00209702','1389.83','2020-11-01 00:14:00','Sync Meter'),(49656,'4A60193390662','2068.3','2020-11-01 00:15:40','Generator'),(49657,'00209701','1476.61','2020-11-01 00:16:10','Sync Meter'),(49658,'00209702','1389.84','2020-11-01 00:16:40','Sync Meter'),(49659,'4A60193390662','2068.3','2020-11-01 00:18:20','Generator'),(49660,'00209701','1476.61','2020-11-01 00:18:51','Sync Meter'),(49661,'00209702','1389.84','2020-11-01 00:19:21','Sync Meter'),(49662,'4A60193390662','2068.3','2020-11-01 00:21:01','Generator'),(49663,'00209701','1476.61','2020-11-01 00:21:31','Sync Meter'),(49664,'00209702','1389.85','2020-11-01 00:22:01','Sync Meter'),(49665,'4A60193390662','2068.3','2020-11-01 00:23:42','WAPDA'),(49666,'00209701','1476.62','2020-11-01 00:24:12','Sync Meter'),(49667,'00209702','1389.86','2020-11-01 00:24:42','Sync Meter'),(49668,'4A60193390662','2068.3','2020-11-01 00:26:22','WAPDA'),(49669,'00209701','1476.63','2020-11-01 00:26:53','Sync Meter'),(49670,'00209702','1389.88','2020-11-01 00:27:23','Sync Meter'),(49671,'4A60193390662','2068.3','2020-11-01 00:29:03','WAPDA'),(49672,'00209701','1476.63','2020-11-01 00:29:33','Sync Meter'),(49673,'00209702','1389.88','2020-11-01 00:30:03','Sync Meter'),(49674,'4A60193390662','2068.3','2020-11-01 00:31:44','WAPDA');
Same is in SQL Fiddle
What I have done
I am able to carry out the start and end date time of a source named WAPDA and in that time I have carried of the MAX value of kwh_t. I want to check it for every hour in 24 hours span. So I have managed the query like that way.
SELECT
msn,
MAX(kwh_t),
MIN(data_date_time),
MAX(data_date_time)
FROM mdc_meters_data
WHERE s_type = 'WAPDA'
AND data_date_time >= DATE '2020-11-01'
AND data_date_time < DATE '2020-11-02'
GROUP BY msn, DATE(data_date_time), HOUR(data_date_time)
ORDER BY msn, DATE(data_date_time), HOUR(data_date_time);
The above query gives me
msn | MAX(kwh_t)| MIN(data_date_time) | MAX(data_date_time)
=======================================================================
4A60193390662| 2068.3 | 2020-11-01T00:02:17Z | 2020-11-01T00:31:44Z
What I want?
The above result is not correct as seen in Fiddle at 2020-11-01T00:02:17Z the s_type is WAPDA and at 2020-11-01T00:12:59Z the s_type is Generator. Then again at 2020-11-01T00:23:42Z the s_type is again WAPDA and so on. I want to set my query in a way that it will give proper information according to the s_type like below
For WAPDA
msn | MAX(kwh_t)| MIN(data_date_time) | MAX(data_date_time)
=======================================================================
4A60193390662| 2068.3 | 2020-11-01T00:02:17Z | 2020-11-01T00:10:19Z
4A60193390662| 2068.3 | 2020-11-01T00:23:42Z | 2020-11-01T00:31:44Z
For Generator
msn | MAX(kwh_t)| MIN(data_date_time) | MAX(data_date_time)
=======================================================================
4A60193390663| 1000.3 | 2020-11-01T00:12:59Z | 2020-11-01T00:21:01Z
As there is no record for the s_type = WAPDA after 2020-11-01T00:10:19Z and before 2020-11-01T00:22:01Z so the query must start from the value of that particular s_type from where it records began. Same is applied for s_type=Generator
How to achieve it?
Any help would be highly appreciated
This is a gaps and islands problem. To solve your problem, you need to also group your readings according to the s_type value, so that (in your sample data) you extract two distinct groups of WAPDA values (separated by the Generator values). Basically you need to keep an overall row number as well as a row number for each island (so counting restarts whenever s_type changes). Subtracting the latter from the former gives you a constant number for each island, on which you can then group.
This is a tricky problem to solve in MySQL 5.x because of the lack of the ROW_NUMBER function, however that functionality can be emulated using variables. This query should give the results you want:
SELECT msn,
s_type,
MAX(kwh_t) AS max_kwh,
MIN(data_date_time) AS min_date_time,
MAX(data_date_time) AS max_date_time
FROM (
SELECT md.*,
#rn := #rn + 1 AS rn,
#rst := CASE
WHEN #st = s_type THEN #rst + 1
WHEN #st := s_type THEN 1
ELSE 1
END AS rst
FROM (
SELECT *
FROM mdc_meters_data
WHERE s_type != 'Sync Meter'
AND data_date_time >= '2020-11-01'
AND data_date_time < '2020-11-02'
ORDER BY data_date_time
) md
CROSS JOIN (SELECT #rn := 0, #rst := 0, #st := '') init
) m
WHERE s_type = 'WAPDA'
GROUP BY msn, rn - rst, DATE(data_date_time), HOUR(data_date_time)
ORDER BY msn, min_date_time
Output (for your sample data):
msn s_type max_kwh min_date_time max_date_time
4A60193390662 WAPDA 2068.3 2020-11-01 00:02:17 2020-11-01 00:10:19
4A60193390662 WAPDA 2068.3 2020-11-01 00:23:42 2020-11-01 00:31:44
Demo (also showing results for s_type = 'Generator') on dbfiddle.
I have a table of events, each of which has a start date and an end date.
I need to display a list of days and show which events are occurring on each day.
E.g. Say I have on event that runs mon-wed and another that runs tues-thurs I'm trying to create a table like so:
Mon: Event 1
Tue: Event 1, Event 2
Wed: Event 1, Event 2
Thu: Event 2
The only way I can see to do this is either by running a query for each day or by loading all events for given date range and then duplicating them in my code if they last for more than one day. Both approaches seem hacky and I'm sure I'm missing something.
Is there a neater way to do this?
Structure:
id INT
name VARCHAR
start_date DATE
end_date DATE
Current query (slightly simplified because this database structure is appalling):
SELECT *
FROM events
WHERE start_date <= $somedate
AND end_date >= $somedate
...where $somedate is a given date. (Yes, I am escaping it properly in my code!)
Select your events for a particular date range (I assume a particular month). Then loop over the days in that month and have another, inner loop that displays any events that occur on that date.
<?php
$events = getEvents(); // some function that returns events from database
echo '<ol class="calendar">';
for ($i = 1; $i <= cal_days_in_month(); $i++) {
echo '<li>';
$beginning = mktime(0, 0, 0, date('n'), $i, date('Y'));
$end = mktime(23, 59, 59, date('n'), $i, date('Y'));
$events_on_day = array();
foreach ($events as $event) {
if ($event->start_date <= $end && $event->end_date >= $beginning) {
$events_on_day[] = $event;
}
}
if ($events_on_day > 0) {
echo '<ul>';
foreach ($events_on_day as $event_on_day) {
echo '<li>' . $event_on_day->name . '</li>';
}
echo '</ul>';
}
}
echo '</ol>';
?>
There's probably a better way, but off the top of my head I would say to create a table of possible dates, then simply
select * from events
inner join possibleDates on possibleDates.Date >= start_date and possibleDates.Date <= end_date
First you'll propably have to get all dates between start_date and end_date of each event.
Put the in a temp. table like:
|Weekday| Event_name|
|Mo | Event1 |
|Tu | Event1 |
|We | Event1 |
|We | Event2 |
|Th | Event2 |
|Fr | Event2 |
and then group_concat the events by group by on weekday.
This link will help you to get the dates between start and end date of each event.:
Get a list of dates between two dates
You can do it in one query if you must, though I would advise getting a weekday-table like Jan Zeiseweis also suggests. Working SQLfiddle: http://www.sqlfiddle.com/#!2/e618d9/1/0
SELECT wk.day, GROUP_CONCAT(e.name, '') events
FROM (
SELECT 'Monday' day, 0 dayIndex
UNION
SELECT 'Tuesday' day, 1 dayIndex
UNION
SELECT 'Wednesday' day, 2 dayIndex
UNION
SELECT 'Thursday' day, 3 dayIndex
UNION
SELECT 'Friday' day, 4 dayIndex
UNION
SELECT 'Saturday' day, 5 dayIndex
UNION
SELECT 'Sunday' day, 6 dayIndex
) wk
LEFT JOIN Events e
ON WEEKDAY(e.start) <= wk.dayIndex
AND WEEKDAY(e.end) >= wk.dayIndex
GROUP BY wk.day ORDER BY wk.dayIndex
I'm getting a weird return when executing this query :
SELECT * FROM rrp
WHERE end > "2012-12-31"
nothing is returned, although I have one row on this table which "end" column is greater than "2012-12-31":
rrp
id_r | id__b | start | end | quantity
27 29 2012-01-01 2012-05-05 1
31 29 2012-11-01 2013-01-01 1
EDIT : startand endare date fields
EDIT : I used wrong database for my tests => wrong result
the issue was coming from Zend_Date when adding a day to a date:
$start = "2012-12-31";
$nStart = new Zend_Date($start, "YYYY-MM-dd");
$end = new Zend_Date($nStart);
$end->addDay(1);
When i echoed $end : echo $end->get("YYYY-MM-dd");
it outputs 2013-12-31
Most likely an issue with how the dates are formatted
This should help
http://dev.mysql.com/doc/refman/5.0/en/using-date.html
If end is a DATE column, it should work as expected:
SELECT
STR_TO_DATE('2013-01-01', '%Y-%m-%d') < "2012-12-31",
STR_TO_DATE('2012-05-05', '%Y-%m-%d') < "2012-12-31"
... returns 0, 1 in my box.
The only possible flaw I can think of is that your system's default date format is not %Y-%m-%d:
SELECT ##DATE_FORMAT
In that case, you need to specify a format every time:
SELECT *
FROM rrp
WHERE end > STR_TO_DATE('2012-12-31', '%Y-%m-%d')