If statement with multiple statements inside loops doesn't work - mysql

I have the follow procedure :
DELIMITER $$
CREATE PROCEDURE getCost(
in p_idp int(11),
out p_cost double)
BEGIN
DECLARE strt double;
DECLARE stop double;
DECLARE diff double;
DECLARE p_hs INTEGER;
DECLARE p_hf INTEGER;
DECLARE p_hcost double;
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE i INTEGER;
-- declare cursor
DECLARE tariffe_cursor CURSOR FOR
SELECT hs,hf,cost FROM tariffe ORDER BY hs;
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
SELECT UNIX_TIMESTAMP(data_inizio) INTO strt
FROM prenotazioni WHERE IdP = p_idp;
SET stop = UNIX_TIMESTAMP();
SET diff = stop - strt;
SET diff = diff / 3600;
SET i = 0;
SET p_cost = 0;
WHILE i < diff
DO
OPEN tariffe_cursor;
get_tariffe: LOOP
FETCH next FROM tariffe_cursor INTO p_hs,p_hf,p_hcost;
IF v_finished = 1 THEN
LEAVE get_tariffe;
END IF;
IF (i >= p_hs AND i < p_hf) THEN
SET p_cost = p_cost + p_hcost;
SET v_finished = 1;
END IF;
END LOOP get_tariffe;
CLOSE tariffe_cursor;
SET i = i + 1;
END WHILE;
IF diff < 0.25 THEN
SET p_cost = 0;
END IF;
END$$
DELIMITER ;
Table tariffe has 2 records:
hs = 0, hf = 3, hcost = 3
hs = 3, hf = 1000, hcost = 2
Suppose DIFF = 1.50 -> Expect p_cost to be 6
Suppose DIFF = 3.75 -> Expect p_cost to be 11
but p_cost is always 3
Tried to use some INSERTs (into a temp table) to check the WHILE loop and the cursor loop and realized that the
IF (i >= p_hs AND i < p_hf) THEN
is computed true only when i = 0 (first while loop) but when i > 0 is always computed as false.
F.ex. when i = 1 the first cursor FETCH returns hs=0,hf=3,hcost=3, but IF seems to be false
What I'm doing wrong?
I've also tried (with no success)
IF (i >= p_hs) AND (i < p_hf)
IF i >= p_hs AND i < p_hf
LOGIC:
Diff is the number of hours between start and stop (renting period).
Tariffe Table contains rental cost: from 0 to 3 hours -> 3 euros, from 3 upto 1000 -> 2 euros.
While loop iterates for every single hour of rental
Cursor loop check for the right hourly cost and add it to p_cost

The problem is that you never set v_finished back to 0 when you leave the get_tariffe loop and continue the while i < diff loop. So on subsequent iterations, if v_finished = 1 is always true and you leave the loop before adding to p_cost.
Put
SET v_vinished = 0;
after
OPEN tariffe_cursor;
But I don't think you'll ever get 11 as a result. You do SET v_finished = 1; after adding the first p_hcost, so it will never process the second row of the table. I'm not sure what your intended logic is to get 11. Maybe you should just take out the line that sets v_finished.

Related

MYSQL Conditional Always Evaluating to Else

The below MYSQL conditional from a trigger is always evaluating to the ELSE statement after I have verified the numbers are as expected. If I make the following assumptions: NEW.exit_time = '2019-04-09 11:50:00', OLD.enter_time = '2019-04-09 11:00:00' I expect time_in_minutes = 50, which should then SET NEW.total = 25 if plot_minimum_cost = 25. I have verified that the select statements populating plot_minimum_cost and plot_minute_cost are accurate given that plot_max_cost is functioning correctly and it is using the same logic to retrieve. What am I missing?
DROP TRIGGER IF EXISTS get_total_parking_cost;
DELIMITER $$
CREATE TRIGGER get_total_parking_cost BEFORE UPDATE
ON records
FOR EACH ROW
BEGIN
DECLARE plot_minimum_cost DOUBLE;
DECLARE plot_max_cost DOUBLE;
DECLARE plot_minute_cost DOUBLE;
DECLARE time_in_lot DATETIME;
DECLARE time_in_minutes DOUBLE;
SELECT parking_lots.min_cost INTO plot_minimum_cost
FROM parking_lots
WHERE parking_lots.id = OLD.parking_id;
SELECT parking_lots.max_cost INTO plot_max_cost
FROM parking_lots
WHERE parking_lots.id = OLD.parking_id;
SELECT parking_lots.minutely_cost INTO plot_minute_cost
FROM parking_lots
WHERE parking_lots.id = OLD.parking_id;
SET #time_in_lot = TIMEDIFF(NEW.exit_time, OLD.enter_time);
SET #time_in_minutes = (HOUR(time_in_lot) * 60) + MINUTE(time_in_lot);
IF #time_in_minutes <= 60 THEN
SET NEW.total = plot_minimum_cost;
ELSEIF #time_in_minutes <= 300 THEN
SET NEW.total = time_in_minutes * plot_minute_cost;
ELSE
SET NEW.total = plot_max_cost;
END IF;
END$$
DELIMITER ;
You've declared the local variable time_in_lot and are using it in (HOUR(time_in_lot) * 60) + MINUTE(time_in_lot); but you never actually set it. You set #time_in_lot which is a session variable. Similarly, you are setting #time_in_minutes even though you've declared an time_in_minutes; but in that case you are using the # version for the IF conditions.
Basically, remove all instances of the # character from the trigger and see if that fixes it.

Case not working for my stored procedure

I have created this procedure to insert upc_id and relevent values in the table product_universal_description.
CREATE PROCEDURE veealpha
(
IN s_po_id INT(11),
IN s_supplier_id INT(11),
IN s_location_id VARCHAR(32),
IN s_warehouse_id INT(11),
IN s_user_id INT(11),
OUT message VARCHAR(64),
OUT error_code INT(4)
)
BEGIN
DECLARE temp_upc VARCHAR(32);
DECLARE i INT;
DECLARE finished INTEGER DEFAULT 0;
DECLARE loop_count int(4);
DECLARE upc varchar(32);
DECLARE p_product_id int(11);
DECLARE p_model varchar(64);
DECLARE counter_cursor CURSOR FOR
SELECT product_id,model,quantity FROM product
WHERE model in('CFB0040','CFB0042','CFB0043','CFB0044')
AND quantity > 0;
DECLARE CONTINUE HANDLER FOR 1062
SET message = 'Duplicate Keys Found';
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET finished = 1;
OPEN counter_cursor;
add_data : LOOP
FETCH counter_cursor INTO p_product_id, p_model, loop_count;
SET i = 1;
WHILE loop_count > 0 DO
CASE i
WHEN i < 10 THEN
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-000',i);
WHEN (i >= 10 AND i < 100) THEN
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-00',i);
WHEN (i >= 100 AND i < 1000) THEN
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-0',i);
ELSE
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-',i);
END CASE;
INSERT INTO product_universal_description
(
`upc_id`,
`po_id`,
`supplier_id`,
`location_id`,
`warehouse_id`,
`product_id`,
`model_no`,
`added_by`,
`updated_by`,
`date_added`,
`date_modified`
) VALUES (
temp_upc,
s_po_id,
s_supplier_id,
s_location_id,
s_warehouse_id,
p_product_id,
p_model,
s_user_id,
s_user_id,
NOW(),
NOW()
);
SET i=i+1;
SET loop_count = loop_count - 1;
END WHILE;
IF finished = 1 THEN
LEAVE add_data;
END IF;
END LOOP add_data;
CLOSE counter_cursor;
END
CALL veealpha(123,45,'UP',1,56,#msg,#err);
ON Execution I getting the result like this.
How ever I have given the conditions there for UPC_ID that it should be well mannered as per case. But leaving for i = 1 FOR all it takes the ELSE condition at CASE. Can anybody tell me .. what's wrong happened and how could i get the desired result.
Try:
...
-- CASE i
CASE
WHEN i < 10 THEN
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-000',i);
WHEN (i >= 10 AND i < 100) THEN
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-00',i);
WHEN (i >= 100 AND i < 1000) THEN
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-0',i);
ELSE
SET temp_upc = CONCAT(s_po_id,'-','CFC','-','30','-','APR14','-',p_model,'-',i);
END CASE;
...

MySQL cursor fetching same result twice

I've got a Stored Procedure that checks rows from one table to insert its details into another. I'm using a cursor but I have a big problem: the cursor loops 2 times over the same row. So I get 2 repeated inserts .
Here is the sp code:
IF (SELECT 1 FROM NOVEDADES WHERE LEGAJO_ID = pLEGAJO_ID AND FECHA >= pFECHA AND CONCEPTO_ID != 11 AND CONCEPTO_ID != 13 AND CONCEPTO_ID != 12 LIMIT 1) = 1
THEN
BEGIN
DECLARE vCONCEPTO_ID INT;
DECLARE vMONTO DECIMAL(12,2);
DECLARE vID INT;
DECLARE vDONE INT DEFAULT 0;
DECLARE CURSOR_NOVEDADES CURSOR FOR
SELECT ID
FROM NOVEDADES
WHERE LEGAJO_ID = pLEGAJO_ID
AND FECHA >= pFECHA
AND CONCEPTO_ID != 11
AND CONCEPTO_ID != 13
AND CONCEPTO_ID != 12;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDONE=1;
OPEN CURSOR_NOVEDADES;
SET vDONE = 0;
REPEAT
FETCH CURSOR_NOVEDADES INTO vID;
SELECT CONCEPTO_ID, MONTO INTO vCONCEPTO_ID, vMONTO
FROM NOVEDADES WHERE ID = vID;
INSERT INTO LIQUIDACIONES_DETALLE (LIQUIDACION_ID, CONCEPTO_ID, MONTO)
VALUES(pLIQUIDACION_ID, vCONCEPTO_ID, vMONTO);
UNTIL vDONE END REPEAT;
CLOSE CURSOR_NOVEDADES;
END;
END IF;
variables beggining with "p" are IN parameters, with "v" are common variables.
I must say that the query of the cursor returns only 1 value.
I've tried with LOOP also, but same result.
I've tried "debugging" the procedure inserting some SELECTS and I see the repeated.
Thanks a lot.
On the last iteration through the loop, the fetch is failing. When it does so, you are re-inserting the previous values. Here is one way to fix this:
REPEAT
FETCH CURSOR_NOVEDADES INTO vID;
if ! vdone then
SELECT CONCEPTO_ID, MONTO INTO vCONCEPTO_ID, vMONTO
FROM NOVEDADES WHERE ID = vID;
INSERT INTO LIQUIDACIONES_DETALLE (LIQUIDACION_ID, CONCEPTO_ID, MONTO)
VALUES(pLIQUIDACION_ID, vCONCEPTO_ID, vMONTO);
end
UNTIL vDONE END REPEAT;

MySQL Cursor Fetch not working

I have the following stored procedure that is meant to implement Dijkstra's shortest path algorithm:
CREATE PROCEDURE `Dijkstras`(IN `pids` VARCHAR(512), IN `startP` VARCHAR(8), IN `endP` VARCHAR(8), OUT `dist` DECIMAL(20,10), OUT `eset` VARCHAR(1024))
BEGIN
DECLARE currentP VARCHAR(4);
DECLARE finished INT DEFAULT 0;
DECLARE pt_from, pt_to int;
DECLARE pt_dist decimal(20,10);
DECLARE done INT DEFAULT 0;
DECLARE cur2 CURSOR FOR
select F.id as `from`, T.id as `to`, dist(F.lat, F.lng, T.lat, T.lng)
as dist
from sampledata F, sampledata T
where F.id < T.id and
find_in_set(convert(F.id, char(10)), pids) and
find_in_set(convert(T.id, char(10)), pids)
order by dist;
DECLARE CONTINUE HANDLER FOR not found SET done = 1;
SET currentP= startP;
SET eset = '';
SET dist = 0;
SET done=0;
OPEN cur2; -- this finds pariwise distances in miles.
REPEAT
FETCH cur2 INTO pt_from, pt_to, pt_dist;
SET dist= dist+pt_dist;
SET eset= CONCAT(eset, ',');
IF(currentP=pt_from OR currentP=pt_to) AND
(IN_SET(pt_from,pids) AND IN_SET(pt_to,pids)) THEN
BEGIN
SET dist= dist+ pt_dist;
SET pids= REMOVE_MEMBER(currentP, pids);
SET eset = concat(eset, ',', concat(pt_from, ':', pt_to));
IF left(eset, 1) = ',' then
SET eset = substring(eset, 2); -- remove extra comma.
END IF;
IF currentP=pt_from THEN
SET currentP=pt_to;
ELSE
SET currentP=pt_from;
END IF;
IF currentP= endP THEN
SET finished= 1;
END IF;
END;
END IF;
UNTIL done
END REPEAT;
CLOSE cur2;
END
My issue is that the cursor isn't working properly. When I fetch the current row into pt_from, pt_to, and pt_dist all I get are NULL values. The sampledata table is properly stored in the database and all the point ids in pids are also in the sampledata table. Plus this EXACT code works for another procedure, but reusing it here isn't working.
Anybody know what I'm doing wrong?
The error was that I passed in the point ids like this '12, 15, 18' with spaces in between. MySQL counts the whitespace when it parses the strings, and the id's in the table were listed without spaces. The correct way to pass in the string set is '12,15,18'.

Trigger syntax and IF ELSE THEN

I'd like to create a trigger which count the number of rows with a specific id (id_ort).
If it found more than 5 rows, I need to increment a variable.
Trigger Syntax
BEGIN
DECLARE nb INT;
DECLARE nba INT;
SET nba =0;
SET NEW.`VPLS_ID_NodeB` = CONCAT("21100", LPAD(NEW.`VPLS_ID_NodeB`,4,0));
SET nb = (SELECT COUNT(DISTINCT(`VPLS_ID_aggregation`)) FROM `VPLS_nodeB` WHERE `id_ORT` = NEW.`id_ORT`);
IF(nb > 5) THEN
SET nba = nb + 1;
ELSE
SET nba = nb;
END IF;
SET NEW.`VPLS_ID_aggregation` = CONCAT("21188", LPAD(NEW.`id_ORT`,2,0), LPAD(nba,2,0));
END
However, there is a bug... Even if i've less than 5 rows, the var is incremented each time.
Any ideas? Maybe it's a syntax problem...
Thanks a lot!
you probably forgot to specify a delimiter i've also made a few other changes as you can see
delimiter #
create trigger VPLS_nodeB_before_ins_trig before insert on VPLS_nodeB
for each row
BEGIN
DECLARE nb INT default 0;
DECLARE nba INT default 0;
SET NEW.VPLS_ID_NodeB = CONCAT('21100', LPAD(NEW.VPLS_ID_NodeB,4,0));
SET nb = (SELECT COUNT(DISTINCT(VPLS_ID_aggregation)) FROM VPLS_nodeB WHERE id_ORT = NEW.id_ORT);
IF(nb > 5) THEN
SET nba = nb + 1;
ELSE
SET nba = nb;
END IF;
SET NEW.VPLS_ID_aggregation = CONCAT('21188', LPAD(NEW.id_ORT,2,0), LPAD(nba,2,0));
END#
delimiter ;