I'm using MySql and I have a Policy table with StartDate and EndDate columns.
How can I write a SELECT query to give me a new row for each month in the date range between these 2 columns.
For example if I have a policy with:
Id StartDate EndDate
123456 2011-05-25 2011-07-26
I would want to see:
Id PolicyId StartDate EndDate
1 123456 2011-05-25 2011-06-24
2 123456 2011-06-25 2011-07-24
3 123456 2011-07-25 2011-07-26
I'm not sure about performance because I'm not much experienced with stored procedures so there might be a better approach. Also, you might want to change the structure of the temporary table (aka. PolicyList). Anyway…
This can also be converted into before/after triggers instead of executing it each time.
DROP PROCEDURE IF EXISTS CreatePolicyList;
DELIMITER //
CREATE PROCEDURE CreatePolicyList()
BEGIN
DECLARE origId, done INT DEFAULT 0;
DECLARE startD, endD DATE;
DECLARE cur CURSOR FOR
SELECT id, StartDate, EndDate FROM Policy;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS PolicyList;
CREATE TEMPORARY TABLE PolicyList (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PolicyId INT(11) NOT NULL,
StartDate DATE NOT NULL,
EndDate DATE NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
OPEN cur;
recLoop: LOOP
FETCH cur INTO origId, startD, endD;
IF (done)
THEN LEAVE recLoop;
END IF;
-- following is an alternative to keep records like
-- "2011-05-25, 2011-06-25" in a single record
-- WHILE startD < DATE_SUB(endD, INTERVAL 1 MONTH) DO
WHILE startD < DATE_ADD(DATE_SUB(endD, INTERVAL 1 MONTH), INTERVAL 1 DAY) DO
INSERT INTO PolicyList (PolicyId, StartDate, EndDate)
VALUES (origId, startD,DATE_SUB(
DATE_ADD(startD, INTERVAL 1 MONTH),
INTERVAL 1 DAY
));
SET startD = DATE_ADD(startD, INTERVAL 1 MONTH);
END WHILE;
IF startD >= DATE_SUB(endD, INTERVAL 1 MONTH) THEN
INSERT INTO PolicyList (PolicyId, StartDate, EndDate)
VALUES (origId, startD, endD);
END IF;
END LOOP;
CLOSE cur;
END //
CALL CreatePolicyList;
and then query:
SELECT * FROM PolicyList
ORDER BY PolicyId, StartDate;
Related
I have a query :
insert into fookoo_business
select stat_date, sum(spend), sum(revenue)
from hooloo_business;
that i want to run for each date from '2017-01-20' until yesterday (it means the query will run 434 times if we're at 01/04/2018), for each date separately
(in a loop).
how can i create a loop in Mysql to do it for me?
I have tried:
creating procedure for the query select #stat_date, sum(spend), sum(revenue)
I called 'query'
then :
CREATE PROCEDURE loop_procedure()
BEGIN
SET #stat_date='2018-03-20';
CALL 'query';
REPEAT
SET #stat_date = #stat_date + INTERVAL 1 DAY;
UNTIL #stat_date = CURDATE() END REPEAT;
END
eventually i've used the following logic within a stored procedure to fetch the data:
PROCEDURE `x_monitoring_loop`()
BEGIN
DECLARE i INT;
DECLARE len INT;
SET len = 434;
SET i = 0;
WHILE (i < len) DO
SET #stat_date= CURDATE()-INTERVAL 1 DAY;
SET #stat_date= #stat_date- INTERVAL i DAY;
Insert query;
SET i = i +1;
END WHILE;
This way the query ran 434 times for each day, beginning at current date - 1 day.
I do not know why you want to use a procedure,I think we can just use a query sql to do it:
INSERT INTO fookoo_business
SELECT stat_date, SUM(spend), SUM(revenue)
FROM hooloo_business
WHERE stat_date BETWEEN STR_TO_DATE('2017-01-02', '%Y-%m-%d') -- start date
AND DATE_SUB(NOW(), INTERVAL 1 DAY) -- end date
GROUP BY stat_date;
I want to populate my table "MyDates" with a range of dates as shown in the code below. When I run the code I get this error "Unknown system variable 'dateStart'"
DECLARE
dateStart DATE DEFAULT '2011-01-01';
DECLARE
dateEnd DATE DEFAULT'2011-12-31';
WHILE dateStart<=dateEnd DO
INSERT
INTO
MyDates
(
mydate
)
VALUES
(
dateStart
) ;
SET dateStart=date_add(dateStart,INTERVAL 1 DAY) ;
END WHILE;
END;
I am trying to create a procedure in MySQL that insert weeks (for current year) to my week table. But there is a problem because after first row is added for the next one I get an error: number column cannot be null. I am new to MySQL so I will appreciate any help.
CREATE PROCEDURE generateWeeks()
BEGIN
SET #currentYear = YEAR(CURDATE());
SET #nextYear = #currentYear + 1;
SET #startOfCurrentWeek = CURDATE();
WHILE(#currentYear < #nextYear) DO
SET #endOfCurrentWeek = DATE_ADD(#startOfCurrentWeek , INTERVAL 7 DAY);
SET #weekNumber = WEEK(#startOfCurrentWeek, 3) -
WEEK(#startOfCurrentWeek - INTERVAL DAY(#startOfCurrentWeek)-1 DAY, 3) + 1;
INSERT INTO `week` (`number`, `start_date`, `end_date`)
VALUES (#weekNumber, #startOfCurrentWeek, #endOfCurrentWeek);
SET #startOfCurrentWeek = #endOfCurrentWeek + 1;
SET #currentYear = YEAR(#endOfCurrentWeek);
END WHILE;
END //
DELIMITER ;
EDITED:
Table Creation:
CREATE TABLE `week` (
`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`number` INT(11) NOT NULL,
`start_date` DATE NOT NULL,
`end_date` DATE NOT NULL
)
Why for first while iteration everything is ok (rows is added), but in the next one I get null value in #weekNumber variable ?
The line:
SET #startOfCurrentWeek = #endOfCurrentWeek + 1;
will convert the variable into a integer. Use date_add instead.
Also, instead of using user-defined variables (#endOfCurrentWeek) you better use local variabled (declare v_endOfCurrentWeek date).
I would like to change the interval in this SQL statement, based on a parameter in a stored procedure. I want to use three different intervals: 1 day, 8 hours, 1 hour
CREATE DEFINER= 'dbshizzle' PROCEDURE `getData`(in sD text(17), in sT text(8))
BEGIN
select stime, sval
from tblNumber
where sDix = 'allright'
and timestamp >= now() - interval 1 day
order by timestamp;
END
Should I use an IF statement with an integer parameter, or a text parameter?
How about just adjusting the parameter and passing in the value as hours?
CREATE DEFINER = 'dbshizzle' PROCEDURE `getData`(
in in_sD text(17), -- should change to varchar
in in_sT text(8), -- should change to varchar
in in_hours int
)
BEGIN
select stime, sval
from tblNumber
where sDix = 'allright'
and timestamp >= now() - interval in_hours hour
order by timestamp;
END;
How would I put together a query to display all of the hours in the next week as I want to compare a timetable against this for appointment purposes.
Thanks for any help!
edit--
the expected result would be great as between 9 to 5
| client_date | client_time |
10/01/2010 09:00:00
10/01/2010 10:00:00
10/01/2010 11:00:00
10/01/2010 12:00:00
10/01/2010 13:00:00
10/01/2010 14:00:00
10/01/2010 15:00:00
10/01/2010 16:00:00
10/01/2010 17:00:00
You will need to create a table to store the date and time values.
CREATE TABLE calendarhours (caldaytime DATETIME);
You will then need to create a stored procedure to loop through the two dates and insert the date time values for the time sheet times into the table.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `timesheetdays`(startdate DATETIME, enddate DATETIME)
BEGIN
DECLARE tempdate DATETIME;
DELETE FROM `calendarhours`;
-- set the temp date to 9am of the start date
SET tempdate = DATE_ADD(DATE(startdate), INTERVAL '0 9' DAY_HOUR);
-- while the temp date is less than or equal to the end date, insert the date
-- into the temp table
WHILE ( tempdate <= enddate ) DO
BEGIN
-- insert temp date into temp table
INSERT INTO `calendarhours` (caldaytime) VALUES (tempdate);
-- increment temp date by an hour
SET tempdate = DATE_ADD(tempdate, INTERVAL '0 1' DAY_HOUR);
-- if the temp date is greater than 5 PM (17:00) then increment to the next day
IF TIMEDIFF(tempdate, DATE_ADD(DATE(tempdate), INTERVAL '0 17' DAY_HOUR)) > 0 THEN
BEGIN
-- increment to the next day
SET tempdate = DATE_ADD(DATE(tempdate), INTERVAL '1 9' DAY_HOUR);
-- for business purposes, if the day is a Saturday or a Sunday increment
-- until we reach Monday
WHILE ( DAYNAME(tempdate) = 'Saturday' OR DAYNAME(tempdate) = 'Sunday' ) DO
BEGIN
SET tempdate = DATE_ADD(DATE(tempdate), INTERVAL '1 9' DAY_HOUR);
END;
END WHILE;
END;
END IF;
END;
END WHILE;
-- return all the inserted date and times
SELECT * FROM calendarhours ORDER BY caldaytime;
END
This procedure will then loop through the two dates, starting from 9 am each day and finishing at 5pm each day (17:00). When the time reaches 18:00, the procedure increments to the next day and starts again at 9 am.
If you are doing a standard business week timesheet, then if the day is equal to Saturday or Sunday, it will increment until it reaches Monday.
To test this I used the following statements:
CALL `timesheetdays`(NOW(), DATE_ADD(DATE(NOW()), INTERVAL '5 0' DAY_HOUR));
SELECT * FROM `calendarhours`;
This tests the procedure from today to 5 days from today and shows the hours as required. The first statement adds the records to the table and then returns the records, the second statement returns the records from the table.
you can use a temporary table in a stored procedure.
DELIMITER ;;
DROP PROCEDURE IF EXISTS ListHours ;;
CREATE PROCEDURE ListHours()
BEGIN
DECLARE curDT DATETIME;
DECLARE today DATETIME ;
DECLARE nextSaturday DATETIME;
DECLARE nextSunday DATETIME;
DECLARE iterDate DATETIME;
DECLARE iterDateTime DATETIME;
DECLARE iterBound DATETIME;
DECLARE resDate DATETIME;
DECLARE resTime DATETIME;
DECLARE delta INT;
DROP TABLE IF EXISTS tempNextWeek;
CREATE TEMPORARY TABLE IF NOT EXISTS tempNextWeek
(
client_date VARCHAR(20),
client_time VARCHAR(20)
);
DELETE FROM tempNextWeek;
SET curDT = NOW();
SET today = ADDTIME(SUBTIME(curDT , TIME(curDT)) , '9:0:0');
SET delta = 8 - DAYOFWEEK(today);
SET nextSunday = ADDDATE(today , INTERVAL delta DAY);
SET nextSaturday = ADDTIME(nextSunday , '6 0:0:0');
-- select today , delta , nextSaturday , nextSunday ;
SET iterDate = nextSunday;
WHILE iterDate <= nextSaturday DO
SET iterDateTime = iterDate;
SET iterBound = ADDTIME(iterDateTime, '8:0:0');
WHILE iterDateTIme <= iterBound DO
INSERT tempNextWeek (client_date, client_time) VALUE ( DATE_FORMAT(iterDateTime, '%Y-%m-%d'), DATE_FORMAT(iterDateTime, '%H:%i:%s') );
SET iterDateTime = ADDTIME(iterDateTime , '1:0:0');
END WHILE;
SET iterDate = ADDTIME(iterDate , '1 0:0:0');
END WHILE ;
SELECT * FROM tempNextWeek;
-- drop table if exists tempNextWeek;
END;;
DELIMITER ;
CALL ListHours();