MySQL Move old data between tables - mysql

I have a problem. I am trying to move data that's older than 2 months to a different table, so I created this routine code:
BEGIN
START TRANSACTION;
DECLARE _limit_date DATETIME;
SET _limit_date := DATE_SUB(NOW(), INTERVAL 2 MONTH);
INSERT
INTO UserDataHist
SELECT *
FROM UserData
WHERE DateTimeLocal < _limit_date;
DELETE
FROM UserData
WHERE DateTimeLocal < _limit_date;
COMMIT;
END
But that gives me an error somewhere in the following code:
DECLARE _limit_date DATETIME;
SET _limit_date := DATE_SUB(NOW(), INTERVAL 2 MONTH);
Now I can't find a lot about routine code examples like mine, so I have no idea what is wrong!
Can someone tell me why I my code gives me an error?

Related

Create a loop based on date Mysql

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;

Why is "INTERVAL" not a valid syntax in IF statement

I have a IF THEN ELSE statement in one of my stored prodecures.
if (DAYOFWEEK((SELECT DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY)))=7)
then
SELECT DATE_ADD(daytemp, INTERVAL (_sign * offset.value + 2) DAY) into `day`;
elseif (DAYOFWEEK((SELECT DATE_ADD(_todaydate, INTERVAL _sign * offset.value DAY)))=1)
then
SELECT DATE_ADD(daytemp, INTERVAL (_sign * offset.value + 1) DAY) into `day`;
else
Select (SELECT DATE_ADD(_todaydate, INTERVAL _sign * offset.value DAY)) into `day`;
END if;
where _todaydate is today's date,_sign is either +1 or -1 depending on if you want to find days in future or past and the offset is a number int showing how many days from _todaydate.
The query is meant to return me working day either in past or future depending upon the _sign * offset.value, but the problem is that sql returns me an error saying that "unexpected INTERVAL (interval) in the if statement"
I am not sure why I am getting this problem because the query it self looks fine to me. Can some one please see what I am missing...
Additional Information:
I have this IF statement in a "Select From" statement, Could that be the case of that this error is happening?
Shouldn't your IF statement be like below
if (SELECT DAYOFWEEK(DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY))=7)
Moreover, I see that you are repeating the same condition multiple times, eventually executing the same query multiple times. Instead have this query executed before and store the value to a local variable and use that local variable in your conditional statement rather; which would be much efficient.
Wouldn't the code be much easier to debug and understand, if we avoided repeating long expressions, wrote something like this (to accomplish what it looks like we are trying to achieve):
DECLARE _dow INT;
DECLARE _inc INT;
SELECT DAYOFWEEK(DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY)) INTO _dow ;
CASE _dow
WHEN 7 THEN SET _inc = 2;
WHEN 1 THEN SET _inc = 1;
ELSE SET _inc = 0;
END CASE;
SELECT DATE_ADD(daytemp, INTERVAL (_sign * offset.value + _inc) DAY) INTO `day`;
To answer the question you asked, "why is INTERVAL not a valid syntax in IF statement"...
I'm not aware of any restriction in MySQL stored programs that prohibits the use of the keyword INTERVAL within an IF statement. Obviously, the INTERVAL keyword isn't part of the IF construct; the keyword is only valid in the context of some expressions.
FOLLOWUP
I notice that the rewrite above is not equivalent to the original. In the original, under the ELSE condition, it's DATE_ADD(_todaydate,. That differs from the other two conditions, where it's DATE_ADD(daytemp
A slight re-write to accommodate that difference, adding another variable _bdt, allows us to still just use two SELECT statements...
DECLARE _bdt DATE;
DECLARE _dow INT;
DECLARE _inc INT;
SELECT DAYOFWEEK(DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY)) INTO _dow ;
CASE _dow
WHEN 7 THEN
SET _inc = 2;
SET _bdt = daytemp;
WHEN 1 THEN
SET _inc = 1;
SET _bdt = daytemp;
ELSE
SET _inc = 0;
SET _bdt = _todaydate;
END CASE;
SELECT DATE_ADD(_bdt, INTERVAL (_sign * offset.value + _inc) DAY) INTO `day`;

MySQL fails to add days to a date when month is over

I am trying to get a final date when a number of days (pplazo input) has elapsed, starting on a date (pfecha input), and avoiding to count certain dates (feriado) that are listed on a table.
So far this is what i got to, using a Stored Procedure:
Input parameters:
pfecha -- DATE
pplazo -- INT (11)
PROC:BEGIN
DECLARE i INT(1);
START TRANSACTION;
SET i=1;
lazo:LOOP
IF NOT EXISTS (SELECT * FROM feriados WHERE feriado=pfecha+i)
THEN
SET pfecha=pfecha+1;
SET i=i+1;
END IF;
IF i=pplazo
THEN
LEAVE lazo;
END IF;
END LOOP lazo;
COMMIT;
SELECT pfecha as respuesta;
END
The thing is, when the days to count make the date go pass the end of the month, then the "respuesta" turns to 0000-00-00.
This shouldn't be happening, if I input 15 days starting on the 2016-04-20 then the resulting date should be something like 2016-05-5.
Can you spot my mistake? Could you point me in the right direction?
The correct way to add a number of days to a date is with the DATE_ADD or ADDATE functions, not the + operator. See
lazo:LOOP
IF NOT EXISTS (SELECT * FROM feriados WHERE feriado=DATE_ADD(pfecha, INTERVAL i DAY))
THEN
SET pfecha=DATE_ADD(pfecha, INTERVAL 1 DAY);
SET i=i+1;
END IF;
IF i=pplazo
THEN
LEAVE lazo;
END IF;
END LOOP lazo;

How to set up a WHILE loop with IF statement in MySQL?

I would like to create a stored routine for MySQL that figures out the number of business or working days for a month (Working Days are Monday thru Friday).
It's a syntax error however I don't know what the syntax error is. All it tells me is:
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
near 'WHILE(#daycount < #totaldays) DO IF (WEEKDAY(#checkweekday) < 6)
THEN ' at line 2
My Syntax Error is in the following:
WHILE(#daycount < #totaldays) DO
IF (WEEKDAY(#checkweekday) < 6) THEN
My Code:
SELECT MONTH(CURDATE()) INTO #curmonth;
SELECT MONTHNAME(CURDATE()) INTO #curmonthname;
SELECT DAY(LAST_DAY(CURDATE())) INTO #totaldays;
SELECT FIRST_DAY(CURDATE()) INTO #checkweekday;
SELECT DAY(#checkweekday) INTO #checkday;
SET #daycount = 0;
SET #workdays = 0;
BEGIN
WHILE(#daycount < #totaldays) DO
IF (WEEKDAY(#checkweekday) < 6) THEN
SET #workdays = #workdays+1;
END IF;
SET #daycount = #daycount+1;
SELECT ADDDATE('#checkweekday', INTERVAL 1 DAY) INTO #checkweekday;
END WHILE;
END;
SELECT #workdays;
Is someone able to assist?
UPDATE
I receive the same error with the following bit of code so it probably has something to do with this:
SET #workdays = 0;
IF (WEEKDAY('2013-06-13') < 6) THEN
SET #workdays = #workdays+1;
END IF;
SELECT #workdays;
I have discovered that you cannot have conditionals outside of the stored procedure in mysql. This is why the syntax error. As soon as I put the code that I needed between
BEGIN
SELECT MONTH(CURDATE()) INTO #curmonth;
SELECT MONTHNAME(CURDATE()) INTO #curmonthname;
SELECT DAY(LAST_DAY(CURDATE())) INTO #totaldays;
SELECT FIRST_DAY(CURDATE()) INTO #checkweekday;
SELECT DAY(#checkweekday) INTO #checkday;
SET #daycount = 0;
SET #workdays = 0;
WHILE(#daycount < #totaldays) DO
IF (WEEKDAY(#checkweekday) < 5) THEN
SET #workdays = #workdays+1;
END IF;
SET #daycount = #daycount+1;
SELECT ADDDATE(#checkweekday, INTERVAL 1 DAY) INTO #checkweekday;
END WHILE;
END
Just for others:
If you are not sure how to create a routine in phpmyadmin you can put this in the SQL query
delimiter ;;
drop procedure if exists test2;;
create procedure test2()
begin
select ‘Hello World’;
end
;;
Run the query. This will create a stored procedure or stored routine named test2. Now go to the routines tab and edit the stored procedure to be what you want. I also suggest reading http://net.tutsplus.com/tutorials/an-introduction-to-stored-procedures/ if you are beginning with stored procedures.
The first_day function you need is:
How to get first day of every corresponding month in mysql?
Showing the Procedure is working
Simply add the following line below END WHILE and above END
SELECT #curmonth,#curmonthname,#totaldays,#daycount,#workdays,#checkweekday,#checkday;
Then use the following code in the SQL Query Window.
call test2 /* or whatever you changed the name of the stored procedure to */
NOTE: If you use this please keep in mind that this code does not take in to account nationally observed holidays (or any holidays for that matter).

Whats wrong with this short procedure (MySQL)

Im trying to make a procedure, which will be checking if user is already logged (he got a session, and im checking if his last action was over 15 minutes ago). My procedure looks like this:
CREATE PROCEDURE `isLogged`(in p_sessid VARCHAR(32), out res INT(1))
BEGIN
DECLARE v_customer_id INT(9);
DECLARE v_date DATE;
SELECT customer_id INTO v_customer_id FROM Sessions WHERE sessid=p_sessid;
SELECT expiry_date INTO v_date FROM Sessions WHERE sessid=p_sessid;
SET res=3;
IF v_customer_id > 0 THEN
IF UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(v_date) THEN
DELETE FROM Sessions WHERE sessid=p_sessid;
SET res=1;
ELSE
UPDATE Sessions SET expiry_date=DATE_ADD(NOW(), INTERVAL 15 MINUTE) WHERE customer_id=v_customer_id;
SET res=0;
END IF;
END IF;
END
Can anyone tell, why it always return 1, what means that user is not logged anymore? I were checking manually expression UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(v_date), and it gives me 0 in response, so? Whats going on?
Thanks in advance,
Marcin
The first IF statement should read like this:
UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(DATE_ADD(v_date, INTERVAL 15 MINUTE))
or else NOW will always be greater than the last login date.
You may rewrite/optimize your procedure to function. For example -
CREATE FUNCTION `isLogged`(IN p_sessid VARCHAR(32))
RETURNS INT
BEGIN
DELETE FROM Sessions WHERE sessid = p_sessid AND v_date <= NOW() - INTERVAL 15 MINUTE;
IF ROW_COUNT() > 0 THEN -- check how many rows were deleted
RETURN 1;
ELSE
UPDATE Sessions SET expiry_date = NOW() + INTERVAL 15 MINUTE WHERE customer_id = v_customer_id;
IF ROW_COUNT() > 0 THEN -- check how many rows were updated
RETURN 0;
END IF;
END IF;
RETURN 3;
END
Also, you can try to debug your code to understand the error.
Omg, that was very stupid.
There was a type mismatch. v_date type was a DATE, and this is just a day! Like 2011-12-14.
Solution:
change DATE -> DATETIME.
And now everything works good.
Anyway, thank you for answers.