Mysql Stored Procedure - mysql

Hi i am trying to run a a loop in stored procedure where in i get the sum of the values from the select query based upon the date(curr_date).
I need to loop the date column in my select query(curr_date).
The problem that i am facing is that when i run the while loop it only gets me the 1st entry for the date from the database.
My Mysql stored procedure is as follows:
CREATE PROCEDURE `paf_calculation`(out avg_sum1 float(15,3))
BEGIN
DECLARE day_count int;
DECLARE extra_days int;
DECLARE lookup_weeks int;
DECLARE week_days INT;
DECLARE count decimal;
DECLARE datapoints int;
DECLARE start_date date;
DECLARE previous_days date;
DECLARE sum_extra_days float(15,3);
DECLARE roid int;
DECLARE historylookup_weeks int;
DECLARE avg_sum float;
DECLARE i int;
DECLARE curr_date date;
set i = 0;
SET WEEK_DAYS = 7;
Set count = 0.5;
select datediff('2016-10-10','2016-10-7') into historylookup_weeks;
/** counts the number of days from the current week start and end days */
select datediff('2016-10-10','2016-10-7') into day_count;
/**No of extra days if the current week is more or less than 7 */
SET extra_days = day_count - WEEK_DAYS;
/**calculates the date 56 days from the current start week date */
select date_sub('2016-10-17',interval 56 day) into previous_days ;
/**calculates the datapoints*/
set avg_sum1=0;
Set datapoints = day_count * lookup_weeks;
set i = 0;
set curr_date = '2016-10-08';
while curr_date < '2016-10-17' do
SELECT SUM(actual_volume) into avg_sum FROM volume_trackers WHERE (date_inserted between '2016-08-23' AND '2016-10-17') AND (day_of_week in (dayofweek(curr_date))) and (ro_id=13);
set curr_date=date_add(curr_date,interval 1 day);
set avg_sum1=avg_sum+avg_sum1;
END WHILE;
END

Your query does seem to loop as coded but I would amend the sum_avg1 calculation to allow for nulls returned to avg sum
set avg_sum1=coalesce(avg_sum,0) + avg_sum1;

Related

Update and Insert table rows using a Mysql stored procedure

I have a table book_meetings which have 70000 record and I want to migrate this data into another table with little modification for this I have created a Mysql stored procedure. Records are inserted in new table but values are set as null.
I am selecting only four columns from book_meetings table and wants to insert them in table.
id int
date date
meet_at time
duration_in_hours decimal
What I want is calculate the start_date and end_date based on above values.
For example:
if date ="2017-09-08" , meet_at is "09:00:00" and duration_in_hours is 1.5
then start_date will be "2017-09-08 09:10:00"
end_date= start_date_duration_in_hour
end_date will be "2017-09-08 09:10:00"
start_date = concat date and meet_at
end_date = start_date + duration_in_hours
and insert this values in new table
if there is another better idea then please suggest
CREATE PROCEDURE book_meetings8()
BEGIN
-- Declare local variables
DECLARE done BOOLEAN DEFAULT 0;
DECLARE meet_at TIME;
DECLARE start_date DATETIME;
DECLARE tmp_date VARCHAR(255);
DECLARE end_date DATETIME;
DECLARE end_recurring_date DATE;
DECLARE date1 DATE ;
DECLARE id INTEGER(11);
DECLARE duration DECIMAL(8,2);
DECLARE minutes INTEGER(11);
-- Declare the cursor
DECLARE iter CURSOR
FOR
SELECT id,date, meet_at,duration_in_hours FROM
book_meetings LIMIT 100;
-- Declare continue handler
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
-- Open the cursor
OPEN iter;
-- Loop through all rows
REPEAT
-- Get order number
FETCH iter INTO id,date1,meet_at,duration;
SET minutes = duration * 60;
SET start_date = CAST(date1 as char) + " "+CAST(meet_at as
char);
SET end_date = CAST(start_date as datetime) + INTERVAL
minutes MINUTE;
INSERT INTO
book_meetings_1(start_date,end_date)
VALUES(start_date,end_date);
-- End of loop
UNTIL done END REPEAT;
-- Close the cursor
CLOSE iter;
END;
Well I have solved above problem with single SQL statement (Insertion and updation all record at once without store procedure)
INSERT INTO temp_diary.book_meetings ( id,start_date,end_date) SELECT id,CONCAT(`date`, ' ', `meet_at`) as start_date,DATE_ADD(concat(date,' ',meet_at), INTERVAL `duration_in_hours` HOUR) as end_date FROM estate.book_meetings;

I have a table with a set of data and I would want to display specific records from it using Mysql:

Here is the table: Sorry couldn't depict the table properly here.
Id Date1 Rank1 date2 Rank2
100 1/1/01 1 1/2/01 1
100 1/2/01 1 1/3/01 1
100 1/3/01 1 1/5/01 4
Now, I would want to see the result where the rank changes but the date1 should display the date from which Rank = 1 started,
An output like this:
Id Date1 Rank1 date2 Rank2
100 1/1/01 1 1/5/01 4
Can anyone please let me know how to go about doing this in MYSQL? I thought about using SQL cursor.Is there another way?
I will create a stored procedure and a cursor to iterate through each record.
My stored procedure will look as follows:
CREATE PROCEDURE `GetChangedRank`()
BEGIN
# Variables containing the final result
DECLARE ID INTEGER;
DECLARE DATE1 DATE;
DECLARE Rank1 INTEGER;
DECLARE DATE2 DATE;
DECLARE Rank2 INTEGER;
DECLARE ROWNUM INTEGER DEFAULT 0;
# Temporary variables to store values of each row.
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE ID_VALUE INT;
DECLARE DATE1_VALUE DATE;
DECLARE Rank1_VALUE INT;
DECLARE DATE2_VALUE DATE;
DECLARE Rank2_VALUE INT;
# testtable is the table that contains data
DECLARE RECORDS_CURSOR CURSOR FOR SELECT * FROM testtable;
# To check if we reached the end of the result set
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1;
# Open cursor
OPEN RECORDS_CURSOR;
# Loop to fetch one row at a time
get_records: LOOP
# Fetch row values to different variables
FETCH RECORDS_CURSOR INTO ID_VALUE, DATE1_VALUE, Rank1_VALUE, DATE2_VALUE, Rank2_VALUE
# To track the row number
SET ROWNUM = ROWNUM + 1;
# Quit the loop when the end of resultset is reached.
IF v_finished = 1 THEN
LEAVE get_records;
END IF;
# Assign the first row values to the final values. Date2 and Rank2 will be updated when the rank is changed.
IF ROWNUM = 1 THEN
BEGIN
SET ID = ID_VALUE;
SET DATE1 = DATE1_VALUE;
SET Rank1 = Rank1_VALUE;
SET DATE2 = DATE2_VALUE;
SET Rank2 = Rank2_VALUE;
END;
ELSE
BEGIN
# Date2 and Rank2 is updated with the row values as the rank is changed.
IF Rank1_VALUE != Rank2_VALUE THEN
BEGIN
SET DATE2 =DATE2_VALUE;
SET Rank2 = Rank2_VALUE;
END;
END IF;
END;
END IF;
END LOOP get_records;
# Select the final values
SELECT ID, DATE1, Rank1, DATE2, Rank2;
# Close cursor
CLOSE RECORDS_CURSOR;
END
Once the procedure is created, you can run this procedure as follow
CALL GetChangedRank;
Is this what you want?
SELECT * FROM <table name>
WHERE Rank1 <> Rank2
Try this nested query
Select Id, (select Date1 from TableName group by Rank1) as Date1, Rank1, Date2, Rank2 from TableName where Rank1<>Rank2;

mysql how to assign a date value to a variable

I'm creating a trigger (before insert) in order to add an updated date, starting from an existing date stored in another table.
Seems that my variable dtStart gets the null value.
This is the code:
BEGIN
DECLARE dtStart DATE;
DECLARE dtRenew DATE;
DECLARE numD INT;
SET dtStart = (SELECT dtStart FROM tblCourses WHERE idCourse = NEW.idCourse);
SET numD = (SELECT setting FROM tblSettings WHERE codSetting = 'D_EXPIRE_C');
SET dtRenew = DATE_ADD(dtStart, INTERVAL numD DAY);
SET NEW.dtExpiration = dtRenew;
END

Stock Backtesting

I'm fairly new to MYSQL but I have experience programming in VBA. I'm trying to create a stored procedure which will backtest a strategy against a table of historical stock price data.The procedure will calculate the 20 Day moving average of closing stock price then if the selected day CLOSE has a price that his higher than the moving average a "buy" is initiated. If a trade is currently on, no new "buys" can be placed and if the selected day CLOSE is below the 20 day moving average a "sell" is initiated. Every time a buy or sell is placed the data is recorded in a table created called backtest results. The data I'm using is from http://finance.yahoo.com/q/hp?s=AAPL+Historical+Prices and I placed it into a table. As you can see the the data is in descending order so in order for me to back test I have to start at the earliest date which happens to be at the bottom. The problem I'm having is that no data is being inputted into this newly created table (Buy Date, Buy Price, Sell Date, Sell Price) . Can anyone spot why this is? Also is mysql suited for row-by-row processing? Thanks!
`Begin
DECLARE total_count int;
DECLARE moving_average decimal;
DECLARE move_up int;
DECLARE current_price decimal;
DECLARE count_var int;
DECLARE buy_price decimal;
DECLARE sell_price decimal;
DECLARE trade_on tinyint;
DECLARE account_balance decimal;
DECLARE start_row int;
DECLARE trade_date date;
SET #trade_on = 0;
SELECT #trade_on;
DROP TABLE IF EXISTS backtestresults;
CREATE TABLE backtestresults (buydate date,buyprice decimal, selldate date, sellprice decimal, accountbalance decimal);
SELECT COUNT(*) INTO #total_count FROM AAPL_Prices;
SELECT * FROM AAPL_Prices WHERE Special_ID = #total_count;
SET #start_row = #total_count -19;
SET #account_balance = 100000;
Loop1: WHILE (start_row > 1) DO
SELECT FORMAT(AVG(SClose),2) FROM AAPL_Prices WHERE Special_ID < #start_row + 19 AND Special_ID > #start_row INTO #moving_average;
SELECT SClose FROM AAPL_Prices WHERE Special_ID = #start_row -19 INTO #current_price;
SELECT TradeDate FROM AAPL_Prices WHERE special_ID = #start_row -19 INTO #trade_date;
IF #trade_on = 0 THEN
IF #current_price > #moving_average THEN
SET #buy_price = #current_price;
SET #trade_on = 1;
SET #account_balance = #account_balance - #buy_price;
INSERT INTO backtestresults (buyprice) values (#buy_price);
INSERT INTO backtestresults (buydate) values (#trade_date);
INSERT INTO backtestresults (balance) values (#account_balance);
End If;
END IF;
IF trade_on = 1 THEN
IF #current_price < #moving_average THEN
SET #sell_price = #current_price;
SET #trade_on = 0;
SET #account_balance = #account_balance + #buy_price;
INSERT INTO backtestresults(sellprice) values (#sell_price);
INSERT INTO backtestresults(selldate) values (#trade_date);
INSERT INTO backtestresults(balance) values (#account_balance);
END IF;
END IF;
SET #start_row = #start_row - 1;
END WHILE Loop1;
SELECT #account_balance;
DESCRIBE backtestresults;
SELECT #start_row;
End`

MYSQL - function not returning expected results

I'm building a site for property rentals. I'm doing the search bit now and I'm trying to setup a function I can call for each property. The function needs to grab all rows from the rental_periods table attached to a given property then work out the best (cheapest) weekly price.
I have the following tables setup already.
properties - One line for each property
rental_periods - Multiple lines for each property, tied with id.
Each line is selfcatered or catered.
If selfcatered the price needs to be worked out from prices given in:
WeekDayPerDay - wdpd
WeekEndPerNight - wepn
Monthly price - monthly
Week price - wk
If catered the prices can be given in:
PerPersonPerNight - pppn
PerNight - pn
PerPersonPerWeek - pppw
I need a function that takes a property id and then grabs all periods that apply, then depending on selfcatered/catered works out the price per week that's best.
What I've got so far doesn't seem to be working. It either returns NULL or returns 100000.00 (my upper limit default price).
Here's the code
DELIMITER $$
CREATE FUNCTION get_price(myid INT)
RETURNS VARCHAR(20)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE price decimal(30,3) default 100000.000;
DECLARE id INT;
DECLARE prop_id INT;
DECLARE type enum('catered','selfcatered');
DECLARE name varchar(45);
DECLARE `from` date;
DECLARE `to` date;
DECLARE currency varchar(45);
DECLARE so tinyint;
DECLARE wk decimal(30,3);
DECLARE wepn decimal(30,3);
DECLARE wdpd decimal(30,3);
DECLARE monthly decimal(30,3);
DECLARE extra decimal(30,3);
DECLARE pppn decimal(30,3);
DECLARE pn decimal(30,3);
DECLARE pppw decimal(30,3);
DECLARE minstay int;
DECLARE maxstay int;
DECLARE breakfast varchar(45);
DECLARE annual TINYINT;
DECLARE cur1 CURSOR FOR SELECT * FROM rental_periods WHERE prop_id = myid;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO id, prop_id, type, name, `from`, `to`, currency, so, wk, wepn, wdpd, minstay, maxstay, monthly, extra, pppn, pn, pppw, breakfast, annual;
IF NOT done THEN
IF (#type = "selfcatered") THEN
IF (#wdpd > 0 AND (#wdpd * 7) < #price) THEN
SET price = #wdpd * 7;
END IF;
IF (#wepn > 0 AND (#wepn * 7) < #price) THEN
SET price = #wepn * 7;
END IF;
IF ((#wdpd > 0 AND #wepn > 0) AND
(#wdpd * 5 + #wepn * 2) < #price) THEN
SET price = #wdpd * 5 + #wepn * 2;
END IF;
IF (#monthly > 0 AND (#monthly / (52 / 12)) < #price) THEN
SET price = #monthly / (52 / 12);
END IF;
IF (#wk > 0 AND #wk < #price) THEN
SET price = #wk;
END IF;
ELSE
IF (#pppn > 0 AND (#pppn * 7) < #price) THEN
SET price = #pppn * 7;
END IF;
IF (#pn > 0 AND (#pn * 7) < #price) THEN
SET price = #pn * 7;
END IF;
IF (#pppw > 0 AND (#pppw) < #price) THEN
SET price = #pppw;
END IF;
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
RETURN price;
END $$
i'm hoping/not thats it's something stupid with how I've arranged it, or my lack of pure MySQL.
ANY help would be very helpful.
EDIT:
Here's an example row from rental_periods:
INSERT INTO `rental_periods` (`id`, `prop_id`, `type`, `name`, `from`, `to`, `currency`, `so`, `wk`, `wepn`, `wdpd`, `minstay`, `maxstay`, `monthly`, `extra`, `pppn`, `pn`, `pppw`, `breakfast`, `annual`)
VALUES (64732, 32, 'selfcatered', 'Summer', '2012-06-01', '2012-08-31', NULL, 1, '350', '60', '100', '', '', '', '', NULL, NULL, NULL, NULL, 0);
I'd expect the function to return 350 picked from the per week column. However if the wepn was 30, not 60, I'd expect 210 to come back (worked out from 7 * wepn prices).
The code im testing in SP:
DELIMITER $$
CREATE procedure tmp_get_price(myid INT)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE price decimal(30,3) default 100000.000;
DECLARE id INT;
DECLARE prop_id INT;
DECLARE type enum('catered','selfcatered');
DECLARE name varchar(45);
DECLARE `from` date;
DECLARE `to` date;
DECLARE currency varchar(45);
DECLARE so tinyint;
DECLARE wk decimal(30,3);
DECLARE wepn decimal(30,3);
DECLARE wdpd decimal(30,3);
DECLARE monthly decimal(30,3);
DECLARE extra decimal(30,3);
DECLARE pppn decimal(30,3);
DECLARE pn decimal(30,3);
DECLARE pppw decimal(30,3);
DECLARE minstay int;
DECLARE maxstay int;
DECLARE breakfast varchar(45);
DECLARE annual TINYINT;
DECLARE cur1 CURSOR FOR SELECT id, prop_id, type, name, `from`, `to`, currency, so, wk, wepn, wdpd, minstay, maxstay, monthly, extra, pppn, pn, pppw, breakfast, annual FROM rental_periods WHERE prop_id = myid;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO id, prop_id, type, name, `from`, `to`, currency, so, wk, wepn, wdpd, minstay, maxstay, monthly, extra, pppn, pn, pppw, breakfast, annual;
IF NOT done THEN
IF (type = "selfcatered") THEN
IF (wdpd > 0 AND (wdpd * 7) < price) THEN
SET price = wdpd * 7;
END IF;
IF (wepn > 0 AND (wepn * 7) < price) THEN
SET price = wepn * 7;
END IF;
IF ((wdpd > 0 AND wepn > 0) AND
(wdpd * 5 + wepn * 2) < price) THEN
SET price = wdpd * 5 + wepn * 2;
END IF;
IF (monthly > 0 AND (monthly / (52 / 12)) < price) THEN
SET price = monthly / (52 / 12);
END IF;
IF (wk > 0 AND wk < price) THEN
SET price = wk;
END IF;
ELSE
IF (pppn > 0 AND (pppn * 7) < price) THEN
SET price = pppn * 7;
END IF;
IF (pn > 0 AND (pn * 7) < price) THEN
SET price = pn * 7;
END IF;
IF (pppw > 0 AND (pppw) < price) THEN
SET price = pppw;
END IF;
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
select price;
END $$
still doesnt work... :( am i being stupid... cant see why this wont work..?!?
gets the periods...
goes throught each one...
if the price is less set it....
select price....?!?
if i put multiple selects in... for example inside the cursor.
only the very bottom one fires and returns 100000.000
i've setup all the value fields as decimals and not allowing NULL...
any thoughts when im going wrong...? also tried debug by inserting in to log table... never fires..?!
Need to read more on cursors this seams a good place to start...
http://www.kbedell.com/2009/03/02/a-simple-example-of-a-mysql-stored-procedure-that-uses-a-cursor/