I have a stored procedure to update some rows in MySQL. But when I call the stored procedure, it affects more than actual rows.
Here is my stored procedure:
CREATE DEFINER=`root`#`localhost` PROCEDURE `SP_INSERT_DATA`(
IN `incoming_data` TEXT,
IN `value_array` TEXT,
IN `serial_number` VARCHAR(50),
IN `data_timestamp` VARCHAR(50),
OUT `result_id` INT,
OUT `result_message` VARCHAR(500)
)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE i INT;
DECLARE value_iteration VARCHAR(50);
DECLARE lcl_data_type_id INT;
DECLARE arr_data_type_name VARCHAR(50);
DECLARE affected_data_row_count INT;
DECLARE cstmr_id INT;
DECLARE exit handler FOR 40001
BEGIN
GET DIAGNOSTICS CONDITION 1
#p1 = MYSQL_ERRNO, #p2 = MESSAGE_TEXT;
SET result_id = -2;
SET result_message = CONCAT('RETURNED ERROR NO : ', #p1 , '\r\nMESSAGE TEXT : ',#p2);
ROLLBACK;
END;
DECLARE exit handler for sqlexception
BEGIN
GET DIAGNOSTICS CONDITION 1
#p1 = MYSQL_ERRNO, #p2 = MESSAGE_TEXT;
SET result_id = -999;
SET result_message = CONCAT('RETURNED ERROR NO : ', #p1 , '\r\nMESSAGE TEXT : ',#p2);
ROLLBACK;
END;
START TRANSACTION;
SET i = 1;
SET affected_data_row_count = 0;
SET cstmr_id = 0;
SET result_id = 0;
SET result_message = 'Success';
SELECT id INTO cstmr_id FROM templaricustomers WHERE templaricustomers.customer_serial_number = serial_number LIMIT 1;
IF(cstmr_id <> 0) THEN
WHILE (LOCATE(',', value_array) > 0)
DO
SET arr_data_type_name = SUBSTRING_INDEX(value_array,',',i);
SET value_array = SUBSTRING(value_array, LOCATE(',',value_array) + 1);
SELECT JSON_EXTRACT(incoming_data, arr_data_type_name) INTO value_iteration;
SET arr_data_type_name := SUBSTRING_INDEX(arr_data_type_name, ".", -1);
IF (SELECT COUNT(id) FROM datatypes WHERE datatypes.data_name = arr_data_type_name) > 0 THEN
SELECT id INTO lcl_data_type_id FROM datatypes WHERE datatypes.data_name = arr_data_type_name LIMIT 1;
ELSE
INSERT INTO datatypes (datatypes.data_name,datatypes.description ,datatypes.inserted_date) VALUES(arr_data_type_name,arr_data_type_name,NOW());
SELECT id INTO lcl_data_type_id FROM datatypes WHERE datatypes.data_name = arr_data_type_name LIMIT 1;
END IF;
IF (SELECT COUNT(id) FROM mqttpacket WHERE mqttpacket.data_type_id = lcl_data_type_id AND mqttpacket.customer_id = cstmr_id) > 0 THEN
UPDATE mqttpacket SET mqttpacket.data_value = value_iteration , mqttpacket.inserted_time = data_timestamp WHERE mqttpacket.data_type_id = lcl_data_type_id AND mqttpacket.customer_id = cstmr_id;
ELSE
INSERT INTO mqttpacket (mqttpacket.data_type_id,mqttpacket.customer_id,mqttpacket.data_value,mqttpacket.inserted_time) VALUES(lcl_data_type_id,cstmr_id,value_iteration,data_timestamp);
END IF;
SET affected_data_row_count = affected_data_row_count +1;
END WHILE;
SET result_id = 0;
SET result_message = CONCAT('Query performed successfully. Effected rows : ',CAST(affected_data_row_count AS CHAR));
ELSE
SET result_id = -1;
SET result_message = 'Customer Serial Number not found.';
END IF;
COMMIT;
END
Here is how I call it:
CALL `SP_INSERT_DATA`('{"subcooling":-40,"B1":113,"B2":206,"B3":471,"B4":226,"B5":8,"B6":380,"B7":210,"B8":187,"Discharge":135,"Suction":120,"High_Pressure":90,"Low_Pressure":90,"Evaporation":73,"Condensation":73,"MAX_CMP_SPEED":1100,"Thermal_Limit":748,"SH":46,"EEV_pct":0,"COP":0,"DSH":60,"WaterFlux":8,"FanPower":1,"DeltaTtoStart":0,"DeltaPtoStart":60,"CMP_ROTOR_RPS":0,"SET_CH_FLASH":120,"SET_HP_FLASH":350,"SET_DHW_FLASH":470,"Defrosting":0,"B8_AVERAGE":63,"SET_PLANT":0,"SET_CH_BMS":160,"SET_HP_BMS":200,"SET_DHW_BMS":480,"SET_ACTIVE":200,"SET_DSH":250,"EEV_INJ_pct":0,"LPT":0,"HPT":0,"PLANT_MODE_MANUAL":0,"DHW_MODE_MANUAL":0,"WATER_FLOW":8,"DISCHARGE_TMP":135,"INVERTER_TMP":8,"ENVELOP_ZONE":1,"EEV_A_STEPS":0,"EBM_POWER":1,"EBM_MAX_POWER":106,"COMP_pct_FINAL":0,"TOTAL_POWER_ABSORBED":10,"POWER_OUT_KW":0,"COOLINGCAPACITY":0}' , '$.subcooling,$.B1,$.B2,$.B3,$.B4,$.B5,$.B6,$.B7,$.B8,$.Discharge,$.Suction,$.High_Pressure,$.Low_Pressure,$.Evaporation,$.Condensation,$.MAX_CMP_SPEED,$.Thermal_Limit,$.SH,$.EEV_pct,$.COP,$.DSH,$.WaterFlux,$.FanPower,$.DeltaTtoStart,$.DeltaPtoStart,$.CMP_ROTOR_RPS,$.SET_CH_FLASH,$.SET_HP_FLASH,$.SET_DHW_FLASH,$.Defrosting,$.B8_AVERAGE,$.SET_PLANT,$.SET_CH_BMS,$.SET_HP_BMS,$.SET_DHW_BMS,$.SET_ACTIVE,$.SET_DSH,$.EEV_INJ_pct,$.LPT,$.HPT,$.PLANT_MODE_MANUAL,$.DHW_MODE_MANUAL,$.WATER_FLOW,$.DISCHARGE_TMP,$.INVERTER_TMP,$.ENVELOP_ZONE,$.EEV_A_STEPS,$.EBM_POWER,$.EBM_MAX_POWER,$.COMP_pct_FINAL,$.TOTAL_POWER_ABSORBED,$.POWER_OUT_KW,$.COOLINGCAPACITY,', '123456', '2021-02-24 10:43:00.00' ,#result_id, #result_message);
The table mqttpacket is a system versioned table. Here are the table creation queries.
CREATE TABLE test_database.MQTTPacket(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
data_type_id INT NOT NULL,
customer_id INT NOT NULL,
data_value INT NULL,
row_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START INVISIBLE,
row_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END INVISIBLE,
inserted_time TIMESTAMP(6) NULL DEFAULT NULL,
PERIOD FOR SYSTEM_TIME(row_start,row_end),
FOREIGN KEY (data_type_id) REFERENCES test_database.DataTypes(id),
FOREIGN KEY (customer_id) REFERENCES test_database.templaricustomers(id)
)WITH SYSTEM VERSIONING;
CREATE TABLE `datatypes` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`data_name` VARCHAR(50) NOT NULL COLLATE 'latin1_general_ci',
`inserted_date` DATE NULL DEFAULT NULL,
`description` VARCHAR(50) NULL DEFAULT NULL COLLATE 'latin1_general_ci',
`device_id` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `device_id` (`device_id`) USING BTREE,
CONSTRAINT `datatypes_ibfk_1` FOREIGN KEY (`device_id`) REFERENCES `test_database`.`devices` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
)
CREATE TABLE `templaricustomers` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`customer_serial_number` VARCHAR(50) NOT NULL COLLATE 'latin1_general_ci',
`customer_name` VARCHAR(50) NULL DEFAULT NULL COLLATE 'latin1_general_ci',
`inserted_date` TIMESTAMP(6) NOT NULL DEFAULT current_timestamp(6),
PRIMARY KEY (`id`) USING BTREE
)
So, when I first call the stored procedure, my result_message variable returns "Query performed successfully. Effected rows : 53" however MySql says
Affected rows: 107 Found rows: 0 Warnings: 0 Duration for 1 query: 0.015 sec.
In the second call of the SP, it says
Affected rows: 160 Found rows: 0 Warnings: 0 Duration for 1 query: 0.031 sec.
Thankful for any help in advance.
I'm trying use mysql to iterate through my database and convert strings to have only numbers and . in order to convert that column into a float from a varchar.
However, when I call the stored proc, it doesn't seem to actually change the datatable. I was hoping somebody could help me figure out what's wrong?
use mydb;
SET GLOBAL log_bin_trust_function_creators = 1;
CREATE TABLE IF NOT EXISTS `docs` (
`id` int(6) unsigned NOT NULL,
`rev` int(3) unsigned NOT NULL,
`content` varchar(200) NOT NULL,
PRIMARY KEY (`id`,`rev`)
) DEFAULT CHARSET=utf8;
-- INSERT INTO `-- docs` (`id`, `rev`, `content`) VALUES
-- ('1', '1', '0.0 '),
-- ('2', '1', '2,765'),
-- ('3', '1', '*'),
-- ('4', '1', '0.7665');
DROP FUNCTION IF EXISTS floatify;
DELIMITER //
CREATE FUNCTION floatify(str VARCHAR(200)) RETURNS VARCHAR(16)
BEGIN
DECLARE i, len SMALLINT DEFAULT 1;
DECLARE ret VARCHAR(16) DEFAULT '';
DECLARE c CHAR(1);
SET len = CHAR_LENGTH( str );
REPEAT
BEGIN
SET c = MID( str, i, 1 );
IF c REGEXP '[0-9|.]' THEN
SET ret=CONCAT(ret,c);
END IF;
SET i = i + 1;
END;
UNTIL i > len END REPEAT;
RETURN ret;
END//
DELIMITER ;
DROP PROCEDURE IF EXISTS tofloat;
DELIMITER //
CREATE PROCEDURE tofloat()
BEGIN
DECLARE currentid INT DEFAULT 1;
DECLARE RowCnt BIGINT DEFAULT 0;
SELECT RowCnt = COUNT(*) FROM docs;
WHILE currentid <= RowCnt DO
UPDATE docs
SET content = floatify(content)
WHERE id = currentid;
SET currentid = currentid + 1 ;
END WHILE;
-- ALTER TABLE docs
-- MODIFY content FLOAT NOT NULL DEFAULT 0 ;
END//
DELIMITER ;
-- select * from docs;
CALL tofloat();
select * from docs;
SET RowCnt = (SELECT COUNT(*) FROM docs); fixed it
You can set a variable to be the result of a subquery within a proc.
Get SQL to do the work:
ALTER TABLE t ADD COLUMN cfloat FLOAT;
UPDATE t SET cfloat = 0 + content;
ALTER TABLE t
CHANGE COLUMN content content_str VARCHAR(200) NOT NULL,
CHANGE COLUMN cfloat content FLOAT NOT NULL;
...check the results
ALTER TABLE t
DROP COLUMN content;
My table:
CREATE TABLE `files_processed` (
`filename` varchar(128) NOT NULL,
`uploaded_by` varchar(64) NOT NULL,
`domain` varchar(255) NOT NULL,
`session_id` varchar(64) NOT NULL,
`datetime_uploaded` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`insert_data` tinyint(1) NOT NULL DEFAULT '1',
`generate_positives` tinyint(1) DEFAULT '1',
`generate_negatives` tinyint(1) NOT NULL DEFAULT '0',
`custom_rules` tinyint(1) NOT NULL DEFAULT '0',
`processing_stage` enum('completed','underway','wait','') NOT NULL DEFAULT 'wait',
`scheduled_processing_datetime` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
My trigger:
DELIMITER $$
CREATE TRIGGER `setProcessingData` BEFORE INSERT ON `files_processed` FOR EACH ROW BEGIN
DECLARE vNextDtTime datetime;
DECLARE vDom varchar(255);
SET vDom = new.domain;
SET new.session_id=new.domain;
SELECT max(scheduled_processing_datetime)
INTO vNextDtTime
FROM files_processed
WHERE domain='#vDom';
IF (ISNULL(vNextDtTime))
THEN
SET vNextDtTime := now();
ELSE
SET vNextDtTime := DATE_ADD(vNextDtTime, interval 7 day);
END IF;
SET new.scheduled_processing_datetime := vNextDtTime;
END
$$
DELIMITER ;
My 2 inserts:
INSERT INTO files_processed (filename, uploaded_by, domain)
VALUES ('1.txt', 'hcs.dfc#gmail.com', 'gmail.com');
Above is inserting current timestamp which is as expected
INSERT INTO files_processed (filename, uploaded_by, domain)
VALUES ('2.txt', 'hcs.dfc#gmail.com', 'gmail.com');
Now for this above, I expect the trigger to add 7 days, but it is still treating as current timestamp.
vDom is not equal to #vdom
If you put in the variable it works
# variables are session variables, that can be set and beselected after your insert.
Another think it is better to name a variable _vDom so that you know even in bigger triggers that is a local variable
DROP TRIGGER IF EXISTS `setProcessingData`;
DELIMITER $$
CREATE TRIGGER `setProcessingData` BEFORE INSERT ON `files_processed` FOR EACH ROW BEGIN
DECLARE vNextDtTime datetime;
DECLARE vDom varchar(255);
SET vDom = new.domain;
SET new.session_id=new.domain;
SELECT max(scheduled_processing_datetime)
INTO vNextDtTime
FROM files_processed
WHERE domain= vDom;
IF (ISNULL(vNextDtTime))
THEN
SET vNextDtTime := now();
ELSE
SET vNextDtTime := DATE_ADD(vNextDtTime, interval 7 day);
END IF;
SET new.scheduled_processing_datetime := vNextDtTime;
END
$$
DELIMITER ;
I'm working on an Android program that introduces in a table approximately 15000 integer values(somewhere between 350-500 lines with 32 columns). In the DB I also have other similar values. This 15000 values that I'm talking about represent a processed image, so basically I want to compare the similarity of two images. Now, when I try to compare the values of two images(I'm comparing value by value and count the equal ones), only the data writing process takes about 7 minutes, which is way too long(I want to be able to write and compare at least 5 images in that time). I know that usually you don't work with this kind of things directly in the DB, but do you think that there is anything that I can do, or is it necessary to do this comparison on the server? The values returned by the descriptor came as line elements separated by ',' and each line is separated by ';'. I take each returned element and save it in a tables column. Here is my code:
Split function:
CREATE DEFINER=`root`#`localhost` FUNCTION `strSplit`(textIn longtext, delim varchar(12), count int) RETURNS int(11)
BEGIN
declare splitString INT(11);
SET splitString = replace(substring(substring_index(textIn, delim, count), length(substring_index(textIn, delim, count - 1)) + 1), delim, '');
RETURN splitString;
END
The function that creates the table:
CREATE TABLE IF NOT EXISTS `myguide`.`objectlocation` (
`ObjectLocationId` INT(11) NOT NULL AUTO_INCREMENT,
`ValueObject` LONGTEXT NOT NULL,
`DescriptorSize` INT(11) NOT NULL,
`DescriptionObject` VARCHAR(45) NOT NULL,
`DataInsert` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`InsertBy` VARCHAR(45) NULL DEFAULT NULL,
PRIMARY KEY (`ObjectLocationId`))
ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARACTER SET = utf8
And this is the code that does the insert part:
CREATE DEFINER=`root`#`localhost` PROCEDURE `myguide_sp_info_imageId`(descriptorIn longtext, sizeDescriptor INT)
BEGIN
declare sizeImagesTable INT DEFAULT (select count(*) from objectLocation);
declare descriptorSizeImage INT;
declare descriptor INT;
declare sizeDescriptorImage INT DEFAULT sizeDescriptor;
declare contorInsertImage INT default 1;
declare descriptorForSplit longtext;
declare descriptorImageSaved longtext;
declare descriptorForSplitImageSaved longtext;
/* check if table exist, drop*/
DROP TEMPORARY TABLE IF EXISTS backupObjectLocation;
/* Create temporar table for store info about objectLocation*/
CREATE TEMPORARY TABLE backupObjectLocation (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
idImage int NOT NULL,
descriptorSaved longtext not null,
sizeDescriptorSaved float not null
);
/* check if table exist, drop*/
DROP TEMPORARY TABLE IF EXISTS processImage;
/* Create temporar table for store info about objectLocation*/
CREATE TEMPORARY TABLE processImage (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
descriptorSaved varchar(255) ,
descriptorReceived varchar(255)
);
SET descriptorImageSaved = RTRIM(descriptorIn);
SET descriptorForSplit = REPLACE(descriptorImageSaved, ';', ',');
INSERT INTO backupObjectLocation (idImage, descriptorSaved, sizeDescriptorSaved)
SELECT ObjectLocationId, ValueObject, DescriptorSize FROM objectLocation;
loop_insertDescriptorImage: LOOP
if contorInsertImage > sizeDescriptorImage then
leave loop_insertDescriptorImage;
end if;
SET descriptor = strSplit(descriptorForSplit, ',', contorInsertImage);
INSERT INTO processImage (descriptorReceived) VALUES (descriptor);
SET contorInsertImage = contorInsertImage + 1;
ITERATE loop_insertDescriptorImage;
end LOOP;
loop_table: LOOP
if sizeImagesTable > 1 then
leave loop_table;
end if;
SET descriptorSizeImage = (SELECT sizeDescriptorSaved from backupObjectLocation where id = sizeImagesTable);
loop_image: LOOP
if descriptorSizeImage > 1 then
leave loop_image;
end if;
SET descriptorImageSaved = (SELECT descriptorSaved from backupObjectLocation where id = sizeImagesTable);
SET descriptorForSplitImageSaved = REPLACE(descriptorImageSaved, ';', ',');
SET descriptorSizeImage = descriptorSizeImage + 1;
ITERATE loop_image;
end LOOP;
SET sizeImagesTable = sizeImagesTable + 1;
ITERATE loop_table;
end LOOP;
select descriptorImageSaved;
select * from backupObjectLocation;
select * from processImage;
END
Please help me find a solution.
I am constantly getting a Error code 1062: Duplicate Entry.
The first row insert, but then it fails on the same ID.
So everytime I hit execute it will increment: 1466, 1467, 1468, 1469.
And each time there is the same record entered, so I am assuming the autoincrement is only working for the first iteration.
Table:
'entity':
CREATE TABLE `entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`reg_num` varchar(45) NOT NULL,
`enterprise_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1474 DEFAULT CHARSET=latin1 COMMENT=\'Comment'
Stored procedure:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `tp_to_entityPROC`()
DETERMINISTIC
COMMENT 'stored'
BEGIN
DECLARE done BOOLEAN DEFAULT 0;
DECLARE Tid INT;
DECLARE Tt_name TEXT;
DECLARE allt CURSOR FOR
SELECT training_provider_id, training_provider_name
FROM training_providers;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN allt;
read_loop: LOOP
IF done THEN
LEAVE read_loop;
END IF;
FETCH allt INTO Tid, Tt_name;
SET #id = 0;
SET #t_name = 0;
SET #id = Tid;
SET #t_name = Tt_name;
SET #empty = '';
if (#id != 0) THEN
INSERT INTO entity (name)
VALUES (#t_name);
SET #my_id = LAST_INSERT_ID();
IF #my_id != 0 THEN
UPDATE training_awarded_providers
SET training_awarded_provider_id = #my_id
WHERE training_awarded_provider_id = #id;
END IF;
END IF;
END LOOP;
CLOSE allt;
END
Not sure about the exact error of duplicate entry but your posted code is not going to work.
Your Table schema
CREATE TABLE `entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`reg_num` varchar(45) NOT NULL <-- Here it's non null column
In your store procedure you are trying to insert null to reg_num column which will never succeed
if (#id != 0) THEN
INSERT INTO entity (name)
VALUES (#t_name);