mysql procedures - running total - mysql

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

Related

MySqlException: Subquery returns more than 1 row, for a stored procedure with a cursor

Hello I have the following stored procedure for MySQL but when it is executed in my ASP.NET Core application I get a Subquery returns more than 1 row error. What am I doing wrong here? The equivalent SQL Server version used to work without problems...
-- System Calculates Candidate’s Matching Score based on a Manager’s Answer Weights
CREATE PROCEDURE spSysCalcCandScore
(
IN Candidate_ID INT,
IN Manager_ID INT
)
Begin
DECLARE ansID INT;
DECLARE tempSum INT;
DECLARE Sum INT;
DECLARE Done INT DEFAULT FALSE;
DECLARE MyCursor CURSOR FOR
SELECT Answer_ID FROM Completed_Questionnaire
WHERE Candidate_ID = Candidate_ID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET Done = TRUE;
START TRANSACTION;
OPEN MyCursor;
myloop: LOOP
FETCH MyCursor INTO ansID;
IF Done THEN
LEAVE myloop;
END IF;
SET tempSum = (SELECT Weight_Value FROM Weight WHERE (Answer_ID = ansID AND Manager_ID = Manager_ID));
SET Sum = Sum + tempSum;
END LOOP;
CLOSE MyCursor;
IF (Sum IS NULL) THEN
SET Sum = 0;
END IF;
UPDATE `Interest`
SET Matching_Score = Sum
WHERE (Candidate_ID = Candidate_ID AND Manager_ID = Manager_ID);
COMMIT;
End//

MySQL Set Variables in While-Loop with If-Condition

I am working on a procedure which is doing the following:
With a cursor declared I want to go through all entries of a table to find entries where the given period is covering the one from the cursor.
Example: a student A went to school at grade x from date 3 to date 6. Let's find all who studied with him at least one time for the same class.
The while-loop would be applied to the same table. But I want to just find out if there is at least one entry or not. So the while loop should stop if the first entry appears.
Example: A student B could have visited the same class as A did. But for a year he has been in another class. Just for example.
And here is my problem. I have two variables to set and I get a syntax error.
DELIMITER $$
DROP PROCEDURE IF EXISTS coworkers$$
CREATE PROCEDURE coworkers(
IN gus INT,
IN rus INT,
OUT gto INT
)
BEGIN
DECLARE recCID INT;
DECLARE recSDT DATE;
DECLARE recEDT DATE;
DECLARE done INT DEFAULT FALSE;
DECLARE ctr INT;
DECLARE cwrk CURSOR FOR
SELECT comp_id, start_date, end_date FROM skill_cv_test WHERE usr_id = rus;
DECLARE CONTINUE HANDLER
FOR NOT FOUND
SET done = TRUE;
OPEN cwrk;
SET ctr = 0;
loop_cwrk: WHILE(ctr<1) DO
FETCH cwrk INTO recCID, recSDT, recEDT;
IF EXISTS
(SELECT *
FROM skill_cv_test AS m
WHERE m.usr_Id = gus AND m.usr_id != rus AND (m.start_date < recSDT OR m.end_date <= recEDT) AND m.comp_id = recCID)
THEN
SET ctr = 1,
SET gto = 1;
IF done THEN
LEAVE loop_cwrk;
END IF;
END WHILE loop_cwrk;
CLOSE cwrk;
end $$
delimiter ;
CALL coworkers(2,1,#gto);
I have tried different formats for the section THEN SET... which is the problem.
Here is the error code:
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 ''ctr' := 1,
SET 'gto' ;= 1;
Here you can see what else I have tried (among others). Probably it's a totally wrong approach.
Btw: the Select within the loop is only a placeholder to get the whole procedure work.
But now, what am I doing wrong?
Thanks in advance.
SOLUTION
DELIMITER $$
DROP PROCEDURE IF EXISTS coworkers$$
CREATE PROCEDURE coworkers(
IN gus INT,
IN rus INT,
OUT gto INT
)
BEGIN
DECLARE recCID INT;
DECLARE recSDT DATE;
DECLARE recEDT DATE;
DECLARE done INT DEFAULT FALSE;
DECLARE ctr INT;
DECLARE cwrk CURSOR FOR
SELECT comp_id, start_date, end_date FROM skill_cv_test WHERE usr_id = rus;
DECLARE CONTINUE HANDLER
FOR NOT FOUND
SET done = TRUE;
OPEN cwrk;
SET ctr = 0;
loop_cwrk: WHILE(ctr<1) DO
FETCH cwrk INTO recCID, recSDT, recEDT;
IF EXISTS
(SELECT *
FROM skill_cv_test AS m
WHERE m.usr_Id = gus AND m.usr_id != rus AND (m.start_date < recSDT
OR m.end_date <= recEDT) AND m.comp_id = recCID)
THEN
SET ctr = 1;
SET gto = 1;
END IF;
IF done THEN
LEAVE loop_cwrk;
END IF;
END WHILE loop_cwrk;
CLOSE cwrk;
end $$
delimiter ;
CALL coworkers(2,1,#gto);
You need add END IF for your first IF
IF EXISTS
(SELECT *
FROM skill_cv_test AS m
WHERE m.usr_Id = gus AND m.usr_id != rus AND (m.start_date < recSDT
OR m.end_date <= recEDT) AND m.comp_id = recCID)
THEN
SET ctr = 1;
SET gto = 1;
END IF; -- Add END IF here
IF done THEN
LEAVE loop_cwrk;
END IF;

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 Stored Procedure Select Check Insert

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 )

check if cursor returns anything

How can you in a procedure function in mysql check if the cursor returns anything?
Is it possible to avoid doing the IF (SELECT COUNT(*) FROM stock ... and instead check up on the _cur variable somehow?
procedure function
DELIMITER $$
DROP FUNCTION IF EXISTS `stock_first_available_id` $$
CREATE DEFINER=`dynaccount`#`localhost` FUNCTION `stock_first_available_id`(_running_total_limit INT, _product_id INT, _group_id INT) RETURNS INT
BEGIN
DECLARE _running_count INT default 0;
DECLARE _id INT;
DECLARE _current_id INT;
DECLARE _sum_count INT;
DECLARE _cur CURSOR FOR SELECT id, count FROM stock WHERE group_id=_group_id && type=2 && product_id=_product_id ORDER BY time DESC, id DESC;
IF (SELECT COUNT(*) FROM stock WHERE group_id=_group_id && type=2 && product_id=_product_id) = 0 THEN
RETURN 0;
END IF;
OPEN _cur;
read_loop: LOOP
FETCH _cur INTO _id, _sum_count;
SET _running_count = _running_count + _sum_count;
SET _current_id = _id;
IF _running_count > _running_total_limit THEN
LEAVE read_loop;
END IF;
END LOOP read_loop;
CLOSE _cur;
RETURN _current_id;
END $$
DELIMITER ;
Add a continue handler to your cursor. See exanples from MySQL documentation.
http://dev.mysql.com/doc/refman/5.0/en/cursors.html