MySQL create FUNCTION into Store Procedure - mysql

in my store procedure i want to have simple function to return value. i want to have this Sql command to function ( thats duplicate action in my procedure):
/*************************************************/
CREATE FUNCTION getDelay( INT id(11) )
SET #v_is_new := (SELECT COUNT(id) from `tsms_entry_exit` WHERE DATE_FORMAT(`datetime_in`, '%Y-%m-%d') = CURDATE() );
IF #v_is_new IS NULL THEN
SET #v_delay := SEC_TO_TIME (TIME_TO_SEC(_datetime_in) - TIME_TO_SEC(#v_user_start_time)) ;
ELSE
SET #v_delay :=0;
END IF;
RETURN #v_delay;
/*************************************************/
i want to have that function into below store procedure how to have this action??
CREATE DEFINER=`root`#`localhost` PROCEDURE `tsmsp_post_entry_exit`(IN `_id` INT(11), IN `_user_id` INT(5), IN `_datetime_in` DATETIME, IN `_datetime_out` DATETIME)
NO SQL
BEGIN
DECLARE v_user_start_time INT UNSIGNED;
DECLARE v_delay INT(11);
DECLARE v_pyear INT UNSIGNED;
DECLARE v_mounth INT UNSIGNED;
SET #v_pyear = pyear ( _datetime_in ) ;
SET #v_mounth = pmonth( _datetime_in );
SET #v_user_start_time := (SELECT `start_time` FROM `tsms_range_time` WHERE `user_id` = _user_id);
IF _id IS NULL THEN
/* Check for first record today for calculate Delay*/
SET #v_is_new := (SELECT COUNT(id) from `tsms_entry_exit` WHERE DATE_FORMAT(`datetime_in`, '%Y-%m-%d') = CURDATE() );
/* calculate USER delay */
IF #v_is_new IS NULL THEN
SET #v_delay := SEC_TO_TIME (TIME_TO_SEC(_datetime_in) - TIME_TO_SEC(#v_user_start_time)) ;
ELSE
SET #v_delay :=0;
END IF;
INSERT INTO `tsms_entry_exit`
(
`user_id`,
`datetime_in`,
`datetime_out`,
`delay`,
`period`
)
VALUES
(
_user_id,
_datetime_in,
_datetime_out,
#v_delay,
CONCAT(#v_pyear, #v_mounth)
);
SELECT ROW_COUNT() AS 'Affected rows';
ELSE
BEGIN
/* Check for first record today for calculate Delay*/
SET #v_is_new := (SELECT COUNT(id) from `tsms_entry_exit` WHERE DATE_FORMAT(`datetime_in`, '%Y-%m-%d') = CURDATE() );
/* calculate USER delay */
IF #v_is_new IS NULL THEN
SET #v_delay := SEC_TO_TIME (TIME_TO_SEC(_datetime_in) - TIME_TO_SEC(#v_user_start_time)) ;
ELSE
SET #v_delay :=0;
END IF;
UPDATE `tsms_entry_exit` SET
`user_id`= _user_id,
`datetime_in` = _datetime_in,
`datetime_out`=_datetime_out,
`delay`=_delay,
`period`=_period
WHERE `id` = _id;
SELECT ROW_COUNT() AS 'Affected Update rows';
END;
END IF;
END

You can't define the function inside procedure but you can call the function though. A simplest example would be like below.
Create your function
DELIMITER $$
CREATE FUNCTION getDelay(id int)
returns int
begin
SET #v_is_new := (SELECT COUNT(id) from `tsms_entry_exit`
WHERE DATE_FORMAT(`datetime_in`, '%Y-%m-%d') = CURDATE() );
IF(#v_is_new IS NULL) THEN
SET #v_delay := SEC_TO_TIME (TIME_TO_SEC(_datetime_in) - TIME_TO_SEC(#v_user_start_time)) ;
ELSE
SET #v_delay :=0;
END IF;
RETURN #v_delay;
end $$
DELIMITER ;
Then call the above defined function in your procedure
DELIMITER $$
CREATE PROCEDURE `tsmsp_post_entry_exit`(IN `_id` INT)
BEGIN
DECLARE v_delay INT;
IF _id IS NULL
THEN
select #v_delay := getDelay(_id); <-- Calling Here
END IF;
END $$
DELIMITER ;

Related

MySQL Procedure variable receiving null on count(*)

Why when I do Select count(*) From table1 I receive 300 but if I do SELECT end = COUNT(*) FROM table1; returns null
Here is the fiddle example https://dbfiddle.uk/ZHzoaztV
code snippet:
CREATE TABLE table1(
start int NOT NULL,
id int PRIMARY KEY AUTO_INCREMENT,
counter int NOT NULL,
difference int NOT NULL,
end int NOT NULL
);
CREATE PROCEDURE doWhile()
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE start INT DEFAULT 120;
DECLARE counter INT DEFAULT 1;
DECLARE end INT DEFAULT 300;
WHILE (i <= end) DO
INSERT INTO table1 VALUES (start,null,counter,start+counter,end);
SET i = i+1;
SET counter = counter+1;
END WHILE;
END;
CALL doWhile();
SELECT * FROM table1;
CREATE PROCEDURE insertMore()
BEGIN
DECLARE start INT;
DECLARE counter INT DEFAULT 1;
DECLARE end INT;
SELECT end = COUNT(*) FROM table1;
SELECT start = MAX(id)+1 FROM table1;
-- SELECT COUNT(*) FROM table1;
WHILE (counter <= end) DO
INSERT INTO table1 VALUES (start,null,counter,start+counter,end);
SET counter = counter+1;
END WHILE;
END;
CALL insertMore();
SELECT * FROM table1;
I expected to return 300, so hopefully my function should do it right
You have a problem with start and end Variable
Can you try this :
CREATE PROCEDURE insertMore()
BEGIN
DECLARE start INT;
DECLARE counter INT DEFAULT 1;
DECLARE end INT;
SELECT COUNT(*) into end FROM table1;
SELECT max(id)+1 into start FROM table1;
-- SELECT COUNT(*) FROM table1;
WHILE (counter <= end) DO
INSERT INTO table1 VALUES (start,null,counter,start+counter,end);
SET counter = counter+1;
END WHILE;
END;
Try it here : https://dbfiddle.uk/X6vP3wKW

Not allowed to return a result ? stored procedure mysql

CREATE TABLE ZAMOWIENIA( id_zamowienia INT PRIMARY KEY NOT NULL,
id_uzytkownika INT, kwota_zamowienia DECIMAL(10,2));
INSERT INTO
ZAMOWIENIA VALUES (1,1,20), (2,4 ,5), (3,3,100), (4,1,300),
(5,2,80), (6, 1,150);
SELECT * FROM ZAMOWIENIA;
select
count(id_uzytkownika) from ZAMOWIENIA WHERE id_uzytkownika=1;
DROP
FUNCTION AccountType;
DELIMITER //
CREATE FUNCTION AccountType(
in_id_uzytkownika INT) RETURNS VARCHAR(20) DETERMINISTIC
BEGIN
DECLARE account_type VARCHAR(20);
DECLARE in_id_uzytkownika INT;
DECLARE zamowienia INT;
select count(id_uzytkownika) AS zamowienia
from ZAMOWIENIA
WHERE id_uzytkownika=in_id_uzytkownika;
select zamowienia from zamowienia;
IF zamowienia >10 THEN
SET account_type = 'BRONZE';
END IF;
IF zamowienia >30 THEN
SET account_type = 'SILVER';
END IF;
IF zamowienia >60 THEN
SET account_type = 'GOLD';
END IF;
return account_type;
END // DELIMITER ;
If you want to set a variable to the result of a SELECT query, you need to use SELECT ... INTO variable, not SELECT ... AS variable. Your function is trying to return the result of the SELECT query because it doesn't store the result into a variable.
Or you can use SET statement, which is simpler when you're just setting a single variable.
So replace the two SELECT statements with:
SET zamowienia = (SELECT COUNT(*) FROM from ZAMOWIENIA
WHERE id_uzytkownika=in_id_uzytkownika);
Also, you shouldn't have DECLARE statements for the function parameters. Remove the line
DECLARE in_id_uzytkownika INT;

Clear handler before function return value to procedure mysql

I have the mysql version 5.5.38.
When I call a procedure that call a function inside there, handler condition its activated into function and raise up to procedure. I need that handler condition on function not affect the process on procedure. Included the function and procedure.
function:
DELIMITER $$
CREATE FUNCTION FUNCTION_HOURLY_GAS_CHANGE(INI_DATE DATETIME, TANK INT)
RETURNS INT
NOT DETERMINISTIC
BEGIN
DECLARE END_GAL INT;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET END_GAL = -1;
SET END_GAL = 0;
SELECT GALLONS INTO END_GAL
FROM TLS_TEMP_DATA WHERE FK_TANK = TANK
AND DATE LIKE CONCAT(DATE_FORMAT(DATE_ADD(DATE_FORMAT(INI_DATE, '%Y-%m-%d %H'), INTERVAL 1 HOUR), '%Y-%m-%d %H'),':%')
AND REQUEST_TYPE = 1;
RETURN END_GAL;
END $$
DELIMITER ;
procedure:
DELIMITER $$
CREATE PROCEDURE HOURLY_GAS_CHANGE(IN dateReport char(50), IN tank INT)
BEGIN
DECLARE COMPLETELOOP INT DEFAULT 0;
DECLARE INI_DATE DATETIME;
DECLARE INI_GAL INT;
DECLARE END_GAL INT;
DECLARE DIFF INT;
DECLARE V_HOUR CHAR(50);
DECLARE V_INI_GAL CHAR(50);
DECLARE V_END_GAL CHAR(50);
DECLARE V_DIFF CHAR(50);
DECLARE INITIALDATA CURSOR FOR
SELECT
DATE, GALLONS FROM TLS_TEMP_DATA WHERE FK_TANK = tank
AND (DATE BETWEEN CONCAT(dateReport, ' 00:00:00') AND CONCAT(dateReport, ' 23:59:59')) AND REQUEST_TYPE = 1
ORDER BY ID;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET COMPLETELOOP = 1;
DROP TEMPORARY TABLE IF EXISTS HOURLYGASCHANGE;
CREATE TEMPORARY TABLE HOURLYGASCHANGE(
`HOUR_DATA` CHAR(50) NOT NULL,
`INI_GAL` CHAR(50) NOT NULL,
`END_GAL` CHAR(50) NOT NULL,
`DIFF` CHAR(50) NOT NULL)
ENGINE=MEMORY;
OPEN INITIALDATA;
READ_LOOP: LOOP
FETCH INITIALDATA INTO INI_DATE, INI_GAL;
IF COMPLETELOOP THEN
LEAVE READ_LOOP;
END IF;
SET END_GAL = 1;
SET END_GAL = FUNCTION_HOURLY_GAS_CHANGE(INI_DATE, tank);
IF END_GAL > 0 THEN
SET DIFF = (END_GAL - INI_GAL);
SET V_DIFF = CAST(DIFF AS CHAR(50));
SET V_END_GAL = CAST(END_GAL AS CHAR(50));
ELSE
SET V_DIFF = 'N/A';
SET V_END_GAL = 'NOT UPDATED';
END IF;
SET V_INI_GAL = CAST(INI_GAL AS CHAR(50));
SET V_HOUR = CAST(DATE_FORMAT(INI_DATE, '%H') AS CHAR(50));
INSERT INTO HOURLYGASCHANGE VALUES(V_HOUR, V_INI_GAL, V_END_GAL, V_DIFF);
END LOOP;
close INITIALDATA;
SELECT * FROM HOURLYGASCHANGE;
END $$
DELIMITER ;
I can't fix the problem, but I found a solution to replace the function, I capture empty result into IFNULL function and now I can set a specific value when select show me a empty result.
SELECT (
IFNULL(
(
SELECT ENDTLS.GALLONS
FROM TLS_TEMP_DATA ENDTLS
WHERE ENDTLS.FK_TANK = tank
AND ENDTLS.DATE LIKE ONCAT(DATE_FORMAT(DATE_ADD(DATE_FORMAT(INI_DATE, '%Y-%m-%d %H'), INTERVAL 1 HOUR), '%Y-%m-%d %H'),':%')
AND ENDTLS.REQUEST_TYPE = 1
)
, -1)
) INTO END_GAL;

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 )

MySql stored functions: Not works

I have the following function:
DROP FUNCTION IF EXISTS saveTableRow;
DELIMITER $$
CREATE FUNCTION saveTableRow(adapter_id int(10), view_id int(10),name varchar(255)) RETURNS TINYINT(1)
BEGIN
DECLARE retOK TINYINT DEFAULT 0;
IF (SELECT COUNT(*) FROM `tables` WHERE `adapter_id`=adapter_id AND `view_id`=view_id AND `name`=name ) = 0 THEN
INSERT INTO `tables` (`adapter_id`,`view_id`,`name`) VALUES (adapter_id, view_id, name);
SET retOK = 1;
END IF;
RETURN retOK;
END;
$$
DELIMITER ;
When i call the function to insert a new row with
SELECT saveTableRow(3,1,'Text');
I get the result '0' and there is no new row saved.
It might be a name collision problem. The name of the column is the same with the name of you parameter. You need to change the name of your parameter that is different from the name of your column. eg,
DROP FUNCTION IF EXISTS saveTableRow;
DELIMITER $$
CREATE FUNCTION saveTableRow(
_adapter_id int(10),
_view_id int(10),
_name varchar(255))
RETURNS TINYINT(1)
BEGIN
DECLARE retOK TINYINT DEFAULT 0;
IF (SELECT COUNT(*)
FROM `tables`
WHERE `adapter_id`=_adapter_id AND
`view_id`=_view_id AND
`name`=_name ) = 0 THEN
INSERT INTO `tables` (`adapter_id`,`view_id`,`name`)
VALUES (_adapter_id, _view_id, _name);
SET retOK = 1;
END IF;
RETURN retOK;
END;
$$
DELIMITER ;
change the if as follows as try please:
IF ((SELECT COUNT(*) FROM `tables` WHERE `adapter_id`=adapter_id AND `view_id`=view_id AND `name`=name ) < 1)