How to get the total from 2 column in a week - mysql

How can I get the Total Undertime for each employee per week. per month. I have a view in which it has columns undertime and overtime per day per employee. however i need to get the TotalUndertime per week.
|EmpID |DayofWeek|DatePresent|Overtime |Undertime|
|3050001|Friday |2016-04-01 | |00:01:00 |
|3050001|Monday |2016-04-04 | |01:00:00 |
|3050001|Tuesday |2016-04-05 |00:30:00 | |
|3050001|Wednesday|2016-04-06 |00:30:00 | |
|3050001|Thursday |2016-04-07 |00:05:00 | |
|3050001|Friday |2016-04-08 |00:05:00 | |
If the employee has an Undertime on Monday, the employee can pay for the Undertime on the following days from Tuesday - Friday. Or if the Employee has an Undertime on Tuesday, the employee has Wednesday - Friday to pay for the Undertime. TheTotalUndertime = "00:01:00"` in the table shown above.
I'm just a newbie when it comes to mysql queries using date and time. Should i use function or procedure?
I used this code to get it but it didn't work.
CREATE DEFINER = `root`#`localhost` PROCEDURE `getUndertime` ( IN `varDatePresent` DATE, IN `varEmpID` VARCHAR( 8 ) ) NOT DETERMINISTIC NO SQL SQL SECURITY DEFINER
BEGIN SELECT DAY( LAST_DAY( varDatePresent ) )
INTO #totaldays ;
SET #daycount =0;
WHILE(
#daycount < #totaldays
) DO SELECT Undertime
FROM view_dtr
WHERE EmpID LIKE '%varEmpID%'
AND DatePresent = varDatePresent
INTO #undertime ;
SELECT Overtime
FROM view_dtr
WHERE EmpID LIKE '%varEmpID%'
AND DATE_ADD( DatePresent, INTERVAL 1
DAY )
INTO #overtime ;
SET #totalUndertime = #undertime - #overtime ;
SET #daycount = #daycount +1;
END WHILE;
SELECT #totalUndertime ;
END ;
Any suggestion will help me very much.
Thank You in advance.

Wouldn't Group By do the trick?
SELECT EMPID, Week(DatePresent) as 'WeekNumber',
SEC_TO_TIME(SUM(COALESCE(undertime,0)-COALESCE(overtime,0)) * 3600) as 'TotalUndertime'
FROM table_name GROUP BY EmpID, Week(DatePresent)
Usage: https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_week
Edit: Based on your definition of TotalUndertime. As a side note, I strongly suggest not to use LIKE when filtering your EMPID.

Related

MySQL select data on the basis of source type

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.

MySql whole query returns Error 1690 while parts of it doesn't

I know that Error 1690 is nothing new in mysql but after searching for solution here i just gave up. So here I go, the error I get is:
BIGINT UNSIGNED value is out of range in '(v_from#10 - p_from#1)'
The problem is, I do not have any substraction in my query... honestly i even removed "-" from DATE_FORMAT!
My query is:
SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
select count(distinct user_id) as 'event_count_dis',count(user_id) as 'event_count',DATE_FORMAT(event_time,'%Y%m') as 'data',
getEventCourse(event_desc) as 'Name'
from sys_events c where DATE_FORMAT(event_time,'%Y%m') like '201809'
and event_type in ('Clicked')
group by getEventCourse(event_desc)
order by count(distinct user_id) desc Limit 20
Function getEventCourse(event_desc) works perfectly as it is very simple.
When i dissect this query and tested every part of it separately, everything worked fine... and I just gave up... Maybe some of you have any idea what's wrong? or at least can tell me what the heck is
'(v_from#10 - p_from#1)'
Function getEventCourse:
BEGIN
DECLARE courseName varchar(100);
IF(LOCATE('cid',description) > 0) THEN
SET courseName = (Select courses_name from sys_courses where courses_id = test_baza.extract_json_value(description,'cid'));
ELSEIF(LOCATE('course_id',description) > 0) THEN
SET courseName = (Select courses_name from sys_courses where courses_id = test_baza.extract_json_value(description,'course_id'));
ELSE
SET courseName = null;
END IF;
RETURN courseName;
END
sys_events:
event_id | event_time | event_desc | event_type | user_id
1537919 | 2018-10-12 | {"course_id":"386","element_id":"498"}| Clicked | 1235
Edit:
Ok, it seems that problem appears in "group by" section.

how to count last 7 record of one table using mysql stored procedure ,in my query i want count isprinted as printed when isprinted=1

CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_printnotprintdailyexpenses`(
in i_localBodyId varchar(10),
in i_epId int(20),
out printed INT(20),
out notprinted INT(20)
)
BEGIN
set printed=(select count(isPrinted) from tbl_dailyExpenses
where date((curdate() - 7)) and date(curdate())and
localBodyId =i_localBodyId and epId=i_epId and isPrinted=1 group by CURDATE()-7 );
set notprinted=(select count(isPrinted) from tbl_dailyExpenses
where date((curdate() - 7 )) and date(curdate())and
localBodyId =i_localBodyId and epId=i_epId and isPrinted=0 group by CURDATE()-7 );
END
I don't think you need a procedure. A simple query should suffice. Based on what I have been able to understand from this question (and the other one you asked) this should give you the results you want:
SELECT date,
localBodyId,
epId,
SUM(CASE WHEN isPrinted=1 THEN 1 ELSE 0 END) AS printed,
SUM(CASE WHEN isPrinted=0 THEN 1 ELSE 0 END) AS notprinted
FROM tbl_dailyExpenses
WHERE localBodyId = i_localBodyId AND epId = i_epId AND
date >= NOW() - INTERVAL 7 DAY
GROUP BY date, localBodyId, epId
ORDER BY date DESC
LIMIT 7
In this query you will need to replace i_localBodyId and i_epId with the values you want to test.

List of days with events that occur on that day

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

Compare dates from different years in mySQL

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')