MySQL Stored Procedure Select Check Insert - mysql

So I'm trying to create a stored procedure in MySQL version 5.5.
I'm not sure what is wrong but what I want to accomplish is.
Get record From Table-A that over 7 days old. And then insert into Table-B, but I need to check if it is exist in Table B. If it is exists then skip, else Insert it.
So here is my code:
DROP PROCEDURE IF EXISTS `move_record`;
DELIMITER //
CREATE PROCEDURE `move_record`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE dt DATETIME;
DECLARE uid,value BIGINT(20);
DECLARE category VARCHAR(30);
DECLARE data,comments VARCHAR(255);
DECLARE cancel TINYINT(1) DEFAULT NULL;
DECLARE curs CURSOR FOR SELECT `datetime`,user_id,category,data,comments,cancel FROM `record` WHERE `datetime` < DATE_SUB(CURDATE(), INTERVAL 7 DAY);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN curs;
myloop: LOOP
FETCH NEXT FROM curs INTO dt,uid,category,data,comments,cancel;
IF done THEN
LEAVE myloop;
END IF;
IF NOT EXISTS (SELECT * FROM `record_arc`
WHERE record_arc.`datetime` = dt
AND record.user_id = uid )
INSERT INTO `record_arc` (`datetime`,user_id,category,data,comments,cancel) VALUES (dt,uid,category,data,comments,cancel);
END IF;
END LOOP myloop;
CLOSE curs;
DEALLOCATE curs;
END//
DELIMITER ;

Maybe you can do this without a loop.
INSERT INTO `record_arc`(
`datetime`,
user_id,
category,
data,
comments,
cancel
)
SELECT
`datetime`,
user_id,
category,
data,
comments,
cancel
FROM `record` r
WHERE
`datetime` < DATE_SUB(CURDATE(), INTERVAL 7 DAY)
AND NOT EXISTS(
SELECT 1
FROM `record_arc` r2
WHERE
r2.`datetime` = r.`datetime`
AND r2.user_id = r.user_id
)

Alias name you used it wrongly. Check the below code
IF NOT EXISTS (SELECT 1 FROM `record_arc`
WHERE record_arc.`datetime` = dt
AND record_arc.user_id = uid )

Related

How to use cursors to update some columns according to another column?

I have a table called USER. This table has 2 columns as end_date, access_date. access_date is empty right now but i want to populate it like:
if end_date exists : access_date = end_date + 1 year (anway i can make that operation) but my problem i could not construct the cursor i have not use cursor logic before.
i need something like:
DELIMITER $$
CREATE PROCEDURE user_procedure ()
BEGIN
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_user varchar(100) DEFAULT "";
-- declare cursor for user
DEClARE user_cursor CURSOR FOR
SELECT * FROM USER;
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
OPEN user_cursor;
get_user: LOOP
FETCH user_cursor INTO v_user;
IF v_finished = 1 THEN
LEAVE get_user;
END IF;
-- operation
-- something like:
set #end_date = select from cursor
update expiry... etcs
END LOOP get_user;
CLOSE user_cursor;
END$$
DELIMITER ;
CALL user_procedure();
but the problem i do not know how to define the cursor because as you see in example:
DECLARE v_user varchar(100) DEFAULT "";
i am pretty sure it is wrong and i try to fetch it into
FETCH user_cursor INTO v_user;
So how can i properly define the cursor and fetch as a whole row and make change ?
Edit: some people did not understand and claimed i have asked same question again, ok i will edit the real code, now as below according to people's comment. This update must be applied to each individual row.
set #key = 'bla bla';
delimiter $$
create procedure select_or_insert()
begin
IF EXISTS (select USER_EXPIRY_DATE from USER) THEN
update USER set ACCESS_EXPIRY_DATE = DATE_ADD(USER_EXPIRY_DATE, INTERVAL 1 YEAR);
ELSE IF EXISTS (select USER_START_DATE from USER) THEN
SET #start_date = (select USER_START_DATE from USER);
SET #start_date_to_be_added = aes_decrypt(#start_date,#key)
update USER set ACCESS_EXPIRY_DATE = DATE_ADD(USER_EXPIRY_DATE, INTERVAL 1 YEAR);
END IF;
end $$
delimiter ;
but in here for example:
ELSE IF EXISTS (select USER_START_DATE from USER)
is returning more than 1 row.
You don't need a cursor for that, you can simply use an update statement:
UPDATE User
SET access_date = DATE_ADD(end_date, INTERVAL 1 YEAR)
WHERE end_date IS NOT NULL

Select into multiple varibales with MySQL

I need to write a stored procedure using mysql.
In the repeat loop showing below, if I use something as:
SET VDATEI=(SELECT A.DATEI FROM STAFF_CONVENIOS A WHERE
A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
the stored procedure works well and I get a result set.
But, I need select into multiple variables. Something as:
SELECT
A.DATEI, A.DIAI, A.HORAI
INTO
VDATEI, VDIAI, VHORAI
FROM
STAFF_CONVENIOS A
WHERE
A.CONV_ID = CONVE AND A.STAFF_ID = MED
LIMIT 1;
In this case my stored procedure is broken I get no result set.
How to use select into to multiple variables into stored procedure with temporary tables?
My stored procedure is similar to:
CREATE PROCEDURE P_GETHORARIOS(
IN `MED` BIGINT,
IN `DATAREF` DATE,
IN `ESPEC` BIGINT,
IN `CONVE` BIGINT
)
BEGIN
DECLARE BDONE,BTEMP, BOCUP INT;
DECLARE DIA;
DECLARE VDIA,OK TINYINT;
DECLARE VDURACAO TINYINT;
DECLARE VDATEI DATE;
DECLARE VDIAI TINYINT;
DECLARE VHORAI TIME;
DECLARE VHORA, VHORAI,VHORAF TIME;
DECLARE CURS CURSOR FOR SELECT DIA,COALESCE(A.DURACAO,30) AS DURACAO, A.HINI FROM STAFF_ESCALA A
WHERE A.DIA=DIA;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET BDONE = 1;
DROP TEMPORARY TABLE IF EXISTS TBLRESULTS;
CREATE TEMPORARY TABLE IF NOT EXISTS TBLRESULTS (
DATA_AG DATE,
DIA TINYINT,
HORA TIME );
SET DIA=DAYOFWEEK(DATAREF);
OPEN CURS;
SET BDONE = 0;
REPEAT
SET OK=TRUE;
FETCH CURS INTO VDIA,VDURACAO,VHORAI;
-- SET VDATEI=(SELECT A.DATEI FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
SELECT A.DATEI, A.DIAI,A.HORAI INTO VDATEI, VDIAI,VHORAI FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1;
SET BTEMP=IF(VDATEI IS NULL,TRUE,FALSE);
SET OK=OK AND BTEMP ;
IF (OK) THEN
INSERT INTO TBLRESULTS VALUES (DATAREF,VDIA,VHORA);
ELSE INSERT INTO TBLRESULTS VALUES (VDATEI,VDIAI,VHORAI);
END IF;
UNTIL BDONE END REPEAT;
CLOSE CURS;
SELECT A.* FROM TBLRESULTS;
END
I have posted a sample of my problem. Here is the real stored procedure:
CREATE DEFINER=`SYSDBA`#`%` PROCEDURE `P_GETHORARIOS`(
IN `MED` BIGINT,
IN `DATAREF` DATE,
IN `ESPEC` BIGINT,
IN `CONVE` BIGINT
)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE BDONE INT;
DECLARE BTEMP TINYINT;
DECLARE BOCUP TINYINT;
DECLARE DIA BIGINT;
DECLARE VDIA TINYINT;
DECLARE VDURACAO TINYINT;
DECLARE VHORA, VHORAI,VHORAF TIME;
DECLARE VMED_ID BIGINT;
DECLARE VESPEC_ID BIGINT;
DECLARE VCONV_ID BIGINT;
DECLARE OK TINYINT;
DECLARE VNOMEESPEC,VNOMEMED VARCHAR(100);
DECLARE CURS CURSOR FOR SELECT DIA,COALESCE(A.DURACAO,30) AS DURACAO, A.HINI, A.HFIM, A.STAFF_ID,B.NOME AS NOMESTAFF, A.ESPEC_ID,C.NOME AS NOMEESPEC
FROM STAFF_ESCALA A
LEFT JOIN STAFF B ON B.ID=A.STAFF_ID
LEFT JOIN ESPECIALIDADES C ON C.ID=A.ESPEC_ID
WHERE A.DIA=DIA;
-- DECLARE CURS CURSOR FOR SELECT HINI, HFIM FROM STAFF_ESCALA;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET BDONE = 1;
DROP TEMPORARY TABLE IF EXISTS TBLRESULTS;
CREATE TEMPORARY TABLE IF NOT EXISTS TBLRESULTS (
DATA_AG DATE,
DIA TINYINT,
HORA TIME,
MED_ID BIGINT,
NOME_MED VARCHAR(100),
ESPEC_ID BIGINT,
NOME_ESPEC VARCHAR(100)
);
SET DIA=DAYOFWEEK(DATAREF);
OPEN CURS;
SET BDONE = 0;
REPEAT
SET OK=TRUE;
FETCH CURS INTO VDIA,VDURACAO,VHORAI,VHORAF,VMED_ID,VNOMEMED,VESPEC_ID,VNOMEESPEC;
IF (MED IS NOT NULL) THEN
SET OK=IF(MED=VMED_ID,TRUE,FALSE) ;
END IF;
IF (ESPEC IS NOT NULL) THEN
SET OK=OK AND IF(ESPEC=VESPEC_ID,TRUE,FALSE) ;
END IF;
IF (CONVE IS NOT NULL) THEN
-- SET #EOK=(SELECT 1 FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
SELECT 1 INTO #EOK FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1;
SET BTEMP=IF(#EOK IS NULL,TRUE,FALSE);
SET OK= OK AND BTEMP ;
END IF;
IF (OK) THEN
SET VHORA=VHORAI;
IF (VDURACAO IS NULL) THEN
SET VDURACAO=30;
END IF;
WHILE (VHORA <= VHORAF) DO
SET BOCUP=(SELECT 1 FROM AGENDA_STAFF A WHERE A.DATA_MARCADA=DATAREF AND A.HORA_MARCADA=VHORA);
IF (BOCUP IS NULL) THEN
INSERT INTO TBLRESULTS VALUES (DATAREF,VDIA,VHORA,VMED_ID,VNOMEMED,VESPEC_ID,VNOMEESPEC);
END IF;
SET VHORA=ADDTIME(VHORA, VDURACAO * 100);
END WHILE;
SET VHORA=ADDTIME(VHORA, VDURACAO * (-100));
IF (VHORA < VHORAF) THEN
SET VHORA=VHORAF;
SET BOCUP=(SELECT 1 FROM AGENDA_STAFF A WHERE A.DATA_MARCADA=DATAREF AND A.HORA_MARCADA=VHORA);
IF (BOCUP IS NULL) THEN
INSERT INTO TBLRESULTS VALUES (DATAREF,VDIA,VHORA,VMED_ID,VNOMEMED,VESPEC_ID,VNOMEESPEC);
END IF;
END IF;
END IF;
UNTIL BDONE END REPEAT;
CLOSE CURS;
SELECT A.* FROM TBLRESULTS A LEFT JOIN AGENDA_STAFF B ON B.STAFF_ID=A.MED_ID AND B.HORA_MARCADA=A.HORA AND B.DATA_MARCADA=A.DATA_AG;
END
//
The problem is with the lines:
-- SET #EOK=(SELECT 1 FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
SELECT 1 INTO #EOK FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1;
If I use "SET #EOK..." all works well.
If I use SELECT 1 INTO #EOK.. the problem appears.
More info with data
Expected result from call p_gethorarios(7,'2017-11-20',47,21)
"data_ag";"dia";"hora";"med_id";"nome_med";"espec_id";"nome_espec"
"2017-11-20";"2";"08:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"10:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"08:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"10:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
STAFF-ESCALA TABLE
ID;STAFF_ID;DIA;HINI;HFIM;ESPEC_ID;DURACAO;CREATION_TIME;MODIFICATION_TIME;LAST_USER_MODIF
25;7;2;08:00:00;10:00:00;50;;18/11/2017 21:44:02;;1
26;7;6;08:00:00;10:00:00;50;;18/11/2017 21:55:27;;1
27;7;4;08:00:00;10:00:00;50;;18/11/2017 21:55:27;;1
28;7;5;08:00:00;10:00:00;50;;18/11/2017 21:56:36;;1
35;7;3;08:00:00;10:00:00;47;;19/11/2017 19:10:29;;1
36;7;5;08:00:00;10:00:00;47;;19/11/2017 19:10:29;;1
38;7;2;08:00:00;10:00:00;47;;19/11/2017 19:10:29;;1
You may have to use user/session variables (the #xyz kind). The documentation does not explicitly state such, but it only shows examples with them.
https://dev.mysql.com/doc/refman/5.7/en/select-into.html
If it is an issue with the NOT FOUND handler getting triggered from something other than the cursor, you could try structuring your code something like this (very pseudocode):
FETCH
WHILE( NOT DONE )
BEGIN
DO STUFF
SET DONE = FALSE
FETCH
END

update statement in MySQL SP showing missing end error

I have a stored procedure like the following. There is an error showing at the update statement before the cursor declaration. When I remove the cursor statement, the stored procedure works fine. Why can't be there an update statement before the cursor statement?
DROP PROCEDURE IF EXISTS GenerateAlert;
DELIMITER $$
CREATE PROCEDURE GenerateAlert()
BEGIN
DECLARE done INTEGER DEFAULT FALSE;
DECLARE temp_project_id INT DEFAULT 0;
DECLARE temp_finish_time DATETIME DEFAULT NOW();
DECLARE _message_class INT DEFAULT 3;
DECLARE proj_user_id INT DEFAULT 0;
-- get message text template
DECLARE message_template VARCHAR(255) DEFAULT
(
SELECT alert_message_template FROM alerts WHERE id = 6
);
-- get maximum allowed minutes
DECLARE allowed_time INT DEFAULT
(
SELECT alert_value_1 FROM alerts WHERE id = 4
);
-- flag all messages with class 3 to deleted = true
UPDATE messages
SET is_deleted = 1
WHERE messages_class = 3;
DECLARE _cur CURSOR FOR
SELECT d.project_id, MAX(finish_time)
FROM
client_docs AS d INNER JOIN
issues AS i ON d.project_id = i.project_id INNER JOIN
working_times AS t ON i.id = t.issue_id
WHERE
d.status = 1 AND
t.finish_time IS NOT NULL AND
t.category = 1
GROUP BY d.project_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN _cur;
read_loop: LOOP
FETCH _cur INTO temp_project_id, temp_finish_time;
IF done THEN
LEAVE read_loop;
END IF;
-- add more minutes to finish time
SET temp_finish_time = DATE_ADD(temp_finish_time, INTERVAL allowed_time MINUTE);
IF temp_finish_time < NOW() THEN
-- this project must be alerted
-- get project user
SELECT c.staff INTO proj_user_id
FROM
projects AS p INNER JOIN
clients AS c ON p.client_id = c.id
WHERE
p.id = temp_project_id;
END IF;
END LOOP read_loop;
CLOSE _cur;
END
$$
DELIMITER ;
Found the answer: The declaration statments must come before any other transactional statement in MySQL stored procedure.
SQL, missing end, but why? Second comment in the answer.

Mysql stored procedure fetch error

What am I doing wrong?
CREATE DEFINER=`root`#`localhost` PROCEDURE `getAllPoints`()
BEGIN
declare done1, done2, done3, done4, pointAlive BOOLEAN DEFAULT FALSE;
*lots of declaring*
...
*lots of declaring*
declare cur1 cursor for select id, Owner_idOwner, longitude, lat,x,y from Point;
declare continue handler for not found set done1= TRUE;
DROP TEMPORARY TABLE IF EXISTS TEMP;
CREATE temporary TABLE IF NOT EXISTS TEMP (
*lots of stuff*
)ENGINE=MEMORY;
open cur1;
mainLoop: loop
fetch cur1 into pointid, ownerid, pointlong, pointlat, pointx,pointy;
if done1 then
set done1 = FALSE;
close cur1;
leave mainLoop;
end if;
insert into TEMP (тут работает);
BLOCK2:BEGIN
** Black is working right with cursor #1***
END BLOCK2 ;
BLOCK3:BEGIN
** Black is working right with cursor #2***
END BLOCK3;
That's what's not working:
pointid declared int with value "18045" fetched from cur1 cursor
call isAlive(pointid,#Alive,#timeTill);
update TEMP set Open = #Alive, TimeTill= #timeTill where Point_id = pointid;
end loop mainLoop;
select * from TEMP;
After calling isAlive loop seems to be interrupted and select query returns only 1 row with correct value in Open and TimeTill column instead of ~1200rows with correct values when isAlive is not called
END
This is the isAlive stored procedure:
CREATE DEFINER=`root`#`localhost` PROCEDURE `isAlive`(IN iPoint_id int, INOUT Alive int, INOUT timeTill time)
BEGIN
declare pointAlive int;
select count(id) into pointAlive from Schedule where
day = dayofweek(curdate())-1
and Point_id = iPoint_id
and Start < curtime()
and Stop > curtime();
if poinTalive then
select pointAlive,timediff(Stop,curtime()) INTO Alive, timeTill
from Points.Schedule
where day = dayofweek(curdate()) -1
and Point_id = iPoint_id;
else
select pointAlive,timediff(str_to_date(concat(curdate(),' ',#starttime), "%Y-%m-%d %T"),now()) INTO Alive, timeTill
from Points.Schedule
where day = dayofweek(curdate()) -1
and Point_id = iPoint_id;
end if;
END
Can you tell me what am I doing wrong? How can I call isAlive for every pointid ? Thank you

mysql procedures - running total

When trying to run this in the SQL window in phpmyadmin the following error is returned..
SQL
DELIMITER $$
DROP FUNCTION IF EXISTS `stock_in_stock_ids` $$
CREATE DEFINER=`root`#`localhost` FUNCTION `stock_in_stock_ids`(_running_total_limit INT, _product_id INT, _block_id INT) RETURNS TEXT
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE _running_qty INT DEFAULT 0;
DECLARE _id INT;
DECLARE _qty INT;
DECLARE _ids TEXT DEFAULT NULL;
DECLARE _cur CURSOR FOR
SELECT id, qty
FROM stock
WHERE block_id=_block_id && type=2 && product_id=_product_id
ORDER BY time DESC, id DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN _cur;
read_loop: LOOP
FETCH _cur INTO _id, _qty;
IF done THEN
SET _ids = '';
LEAVE read_loop;
END IF;
SET _running_qty = _running_qty + _qty;
SET _ids = CONCAT_WS(',', _ids, _id);
IF _running_qty >= _running_total_limit THEN
LEAVE read_loop;
END IF;
END LOOP read_loop;
CLOSE _cur;
RETURN _ids;
END $$
DELIMITER ;
error
#1418 - This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
update (working solution)
SELECT qty, price_cost, #running_total:=#total running_total, #total:=#total+qty total
FROM stock, (SELECT #running_total:=0, #total:=0) vars
WHERE block_id=101 && type=2 && product_id=20
HAVING running_total<=3000
ORDER BY time DESC, id DESC
You want to use a stored procedure but are using a function. There's a difference, you know?
Also I think you don't need a procedure at all, let alone a cursor. Cursors are expensive as hell.
Does this get you what you want?
SELECT * FROM (
SELECT
id,
qty,
#running_total:=#running_total + qty as running_total
FROM stock
, (SELECT #running_total:=0) vars
WHERE block_id=_block_id && type=2 && product_id=_product_id
ORDER BY time DESC, id DESC
) sq
WHERE running_total <= $yourRunningTotalLimit