Dynamic renaming of Columns based on row values in mysql - mysql

I am trying to rename columns of a new table based on the row values of a table.
I am using a cursor to fetch the column values corresponding to the old table name. Then altering the newly created table to rename the columns by using the values fetched by the cursor.
The following table shows the columns to be remapped from the client_label to master_label for the respective client_id.
CREATE TABLE `mapping_table` (
`_id` int(11) NOT NULL,
`master_label` varchar(50) DEFAULT NULL,
`client_label` varchar(50) DEFAULT NULL,
`org_label` varchar(50) DEFAULT NULL,
`client_id` varchar(3) DEFAULT NULL
);
INSERT INTO `mapping_table` (`_id`, `master_label`, `client_label`,
`organization_label`, `client_id`) VALUES
(1, 'CUST-ID', 'client', 'TEST', 'tes'),
(8, 'TRANSACTION-ID', 'trno', 'TEST', 'tes'),
(9, 'TRANSACTION-DATE', 'date', 'TEST', 'tes'),
(14, 'PROD-NAME', 'product', 'TEST', 'rbb'),
(16, 'SALES-FIRSTNAME', 'firstname', 'TEST', 'tes')
;
The Procedure looks like this..
BEGIN
DECLARE old_names varchar(50) default null;
DECLARE new_names varchar(50) default null;
DECLARE num_cols varchar(3) DEFAULT null;
DECLARE i INT(3) DEFAULT null;
DECLARE cur_old_names CURSOR for SELECT client_label from`mapping_table` where client_id = ip_client_id order by _id;
DECLARE cur_new_names CURSOR for SELECT master_label from `mapping_table` where client_id = ip_client_id order by _id;
BEGIN
if ip_client_id = (SELECT DISTINCT(client_id) from `mapping_table` where client_id = ip_client_id) THEN
CREATE TABLE `test01`
SELECT * FROM `ROOT_TABLE`;
select count(client_id) into num_cols from `mapping_table` where client_id=ip_client_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- open the cursor
OPEN cur_old_names;
OPEN cur_new_names;
my_loop: LOOP
FETCH NEXT FROM cur_new_names INTO val1;
FETCH NEXT FROM cur_old_names INTO val2;
IF done THEN -- this will be true when we are out of rows to read, so we go to the statement after END LOOP.
LEAVE my_loop;
ELSE
ALTER TABLE `test01 ` change val1 val2 varchar(50);
END IF;
END LOOP;
close cur_old_names;
close cur_new_names;
end if;
END;
END
The test01 table should contain column names from the cursor cur_new_names fetched into val2
While executing, I get the error message,
The following query has failed: "SET #p0='tes'; CALL
`map_column_names`(#p0); "MySQL said: #1054 - Unknown column 'val1' in 'test01_normalized_02'

Related

MySQL how to properly check a variable's value from SELECT INTO statement

I have a before insert trigger in a MySQL 8.0 database that checks for the incoming status and passes it along to the stored procedure, which then returns a value to be SET and passed along to be inserted. The stored procedure is being called correctly; however, when checking the entry in the database, the desired value of 1 is expected. However, NULL is there.
Here is the BEFORE_INSERT trigger on the table
CREATE DEFINER=`user`#`` TRIGGER `data_BEFORE_INSERT` BEFORE INSERT ON `data` FOR EACH ROW BEGIN
DECLARE newSearchAddressId INTEGER;
IF NEW.status = 'fresh' THEN
CALL CALC_FRESH_SEARCH_ADDRESS_ID(NEW.lead, #newSearchAddressId);
SET NEW.searchAddressId = #newSearchAddressId;
END IF;
END
Here is what's in the stored procedure:
CREATE DEFINER=`user`#`` PROCEDURE `CALC_FRESH_SEARCH_ADDRESS_ID`(
IN leadId INT,
OUT newSearchAddressId INT
)
proc_label: BEGIN
DECLARE lastSearchAddressID INT;
DECLARE lastStatus VARCHAR(100);
SELECT
`searchAddressId`,
`status`
INTO
lastSearchAddressID,
lastStatus
FROM `leads`
WHERE `id` = leadId;
-- if there is no status previous it's a first time entry
IF lastStatus IS NULL THEN
SET newSearchAddressId = 1;
LEAVE proc_label;
END IF;
END
In the SELECT statement above from leads table I am assured that only one row will be returned.
The desired outcome is that I select those two columns, status and searchAddressId, and if status is NULL, then we know that there is no previous entry and, therefore, a brand new record. Because it is a brand new record, we assign the #newSearchAddressId to the value of 1 and leave the stored procedure early.
I think I am incorrectly setting the variables or checking in the IF statement. That's at least what I think is going on. I have looked at this post and tried setting just one variable to check with an IF statement but the same undesired result of NULL being in the database.
Here is sample data:
DROP TABLE IF EXISTS `data`;
CREATE TABLE `data` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`lead` INT NOT NULL,
`status` VARCHAR(100) NOT NULL,
`searchAddressId INT NOT NULL
) ENGINE=INNODB;
INSERT INTO `data` (`lead`, `status`, `searchAddressId`)
VALUES(1, 'fresh', 1),
VALUES(2, 'suspended', 1),
VALUES(3, 'stale', 1),
VALUES(4, 'fresh', 1),
VALUES(5, 'cancelled', 1);
Based on the data above, here is what I am expecting from the procedure above
DECLARE lastSearchAddressID INT;
DECLARE lastStatus VARCHAR(100);
SELECT `searchAddressId`, `status`
INTO lastSearchAddressID, lastStatus
FROM `data`
WHERE `lead` = 6;
based on the SELECT statement above searchAddressID and lastStatus should be NULL
so when reaching the IF statement of
IF lastStatus IS NULL THEN
SET newSearchAddressId = 1;
LEAVE proc_label;
END IF;
Integer 1 should be assigned to the OUT newSearchAddressId INT in the stored procedure's parameters.
A follow-up query of
SELECT * FROM `data` WHERE `lead` = 6;
Would yield:
id
lead
status
searchAddress
6
6
'fresh'
1
What is yielded:
id
lead
status
searchAddress
6
6
'fresh'
NULL
here is the db fiddle the fiddle is not working but while I fiddle with getting it working I think you can see more clearly the expectations

MySQL optimize comparing function

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.

#1442 - Can't update table ... in stored function/trigger because it is already used by statement which invoked this stored function/trigger

I have this situation:
Two table in two databases:
1st: `persone`.`T_Persone` that contain detailed information about workers plus two fields empty by default: `user_id` and `username`;
2nd: `joomla`.`fe48y_users` that contain information of user in the CMS Joomla including `id` and `username`.
I created a procedure that insert a new user in joomla and return user_id and username of new user created.
I also created also 2 triggers (on update and on insert) that call the procedure and set user_id and username on `T_Persone` table.
I also created a trigger on delete of `joomla`.`fe48y_users` that update `persone`.`T_Persone` and set null to `user_id` and `username` fields.
This is the procedure:
CREATE DEFINER=`root`#`localhost` PROCEDURE `persone_users_upd`(IN `in_id` INT(10) UNSIGNED, IN `new_email` VARCHAR(255), IN `old_email` VARCHAR(255), OUT `out_user_id` INT(10) UNSIGNED, OUT `out_username` VARCHAR(255))
BEGIN
DECLARE has_email Boolean;
DECLARE my_user_id INT;
DECLARE my_username VARCHAR(255);
DECLARE my_name VARCHAR(255);
SELECT (CASE new_email WHEN '' THEN FALSE ELSE TRUE END) INTO #has_email;
IF #has_email THEN
SELECT CONCAT(`Nome`,' ',`Cognome`), COALESCE(`CF`,LOWER(SUBSTR(new_email, 1, INSTR(new_email, '#') - 1))) INTO #my_name, #my_username FROM `T_Persone` WHERE `IDPersona` = in_id;
IF new_email = old_email THEN
INSERT INTO `spmsf`.`fe48y_users` (`name`, `username`, `email`, `password`, `block`, `sendEmail`, `registerDate`, `lastvisitDate`, `activation`, `params`, `lastResetTime`, `resetCount`, `otpKey`, `otep`, `requireReset`) VALUES
(#my_name, #my_username, new_email, '<omissis>', 0, 1, NOW(), '0000-00-00 00:00:00', '', '{"admin_style":"","admin_language":"","language":"","editor":"","helpsite":"","timezone":"Europe/Rome"}', '0000-00-00 00:00:00', 0, '', '', 0) ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `email` = VALUES(`email`);
ELSE
UPDATE `spmsf`.`fe48y_users` SET `email` = #my_email WHERE `email` = new_email;
END IF;
SELECT `id`, `username` INTO #my_user_id, #my_username FROM `spmsf`.`fe48y_users` WHERE `email` = new_email;
INSERT IGNORE INTO `spmsf`.`fe48y_user_usergroup_map` (`user_id`,`group_id`) VALUES (#my_user_id, 10);
SET out_user_id=#my_user_id, out_username=#my_username;
END IF;
END
these are the triggers on `T_Persone`:
CREATE TRIGGER `persone_del` AFTER DELETE ON `T_Persone`
FOR EACH ROW BEGIN
IF OLD.`user_id` IS NOT NULL THEN
DELETE FROM `spmsf`.`fe48y_users` WHERE `id` = OLD.`user_id`;
DELETE FROM `spmsf`.`fe48y_user_usergroup_map` WHERE `user_id` = OLD.`user_id`;
END IF;
END
CREATE TRIGGER `persone_ins` BEFORE INSERT ON `T_Persone`
FOR EACH ROW BEGIN
CALL persone_users_upd(NEW.`IDPersona`,COALESCE(NEW.`Email`,NEW.`Email_alt`),COALESCE(NEW.`Email`,NEW.`Email_alt`), #user_id, #username);
SET NEW.`user_id` = #user_id, NEW.`username` = #username;
END
CREATE TRIGGER `persone_upd` BEFORE UPDATE ON `T_Persone`
FOR EACH ROW BEGIN
CALL persone_users_upd(NEW.`IDPersona`,COALESCE(NEW.`Email`,NEW.`Email_alt`),COALESCE(OLD.`Email`,OLD.`Email_alt`), #user_id, #username);
SET NEW.`user_id` = #user_id, NEW.`username` = #username;
END
and this is the trigger on `fe48y_users` delete:
CREATE TRIGGER `users_del` BEFORE DELETE ON `fe48y_users`
FOR EACH ROW BEGIN
DECLARE my_user_id Int;
SELECT COUNT(*) INTO #my_user_id FROM `personale`.`T_Persone` WHERE `user_id` = OLD.`id`;
IF #my_user_id > 0 THEN
UPDATE `personale`.`T_Persone` SET `user_id` = NULL, `username` = NULL WHERE `user_id` = OLD.`id`;
END IF;
END
SO, I have two problems:
1st: When I try to delete a user in `fe48y_users` I have the error
#1442 - Can't update table 'fe48y_users' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
2nd: When I insert a new person it don't appear in 'fe48y_users' but when I update it than appear.

ORA-02070: database [MySQL] does not support subqueries in this context. - ORACLE

I have the following tables:
MySQL table: member_interact
CREATE TABLE `member_interact` (
`INT_MEMBER_ID` int(11) NOT NULL,
`INT_ID` int(11) NOT NULL AUTO_INCREMENT,
`INT_SOURCE` varchar(1) NOT NULL,
`INT_DATE` datetime DEFAULT NULL,
`INT_TYPE` varchar(30) NOT NULL,
`COPY_TO_STG` varchar(12) NOT NULL DEFAULT 'NO',
`NEW_STG_SEQ` int(11) DEFAULT NULL,
`COPY_TO_STG_DATE` datetime DEFAULT NULL,
PRIMARY KEY (`INT_ID`),
UNIQUE KEY `INT_ID_UNIQUE` (`INT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=31246 DEFAULT CHARSET=utf8$$
Oracle table: MEMBER_INTERACT_MYSQL_STG
CREATE TABLE "JTI_HTP"."MEMBER_INTERACT_MYSQL_STG"
( "INT_MEMBER_ID" NUMBER(10,0) NOT NULL ENABLE,
"INT_ID" NUMBER(10,0),
"INT_SOURCE" NVARCHAR2(1) NOT NULL ENABLE,
"INT_DATE" DATE,
"INT_TYPE" NVARCHAR2(30) NOT NULL ENABLE,
"INSERTING_DATE" DATE,
"MYSQL_ID" NUMBER(12,0)
) SEGMENT CREATION DEFERRED
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
TABLESPACE "USERS" ;
Basically, I need to copy member_interact into member_interact_mysql_stg with adding new columns as follow:
MEMBER_INTERACT_MYSQL_STG.STG_INT_ID = NEW_SEQ
MEMBER_INTERACT_MYSQL_STG.MYSQL_INT_ID = MEMBER_INTERACT.INT_ID
MEMBER_INTERACT.COPY_TO_STG = 'YES', once the copy operation is completed.
MEMBER_INTERACT.NEW_STG_SEQ = MEMBER_INTERACT_MYSQL_STG.STG_INT_ID
I have created the following Procedures:
create or replace PROCEDURE COPY_MYSQL_MOB_INT_TO_STG(
P_BATCH_NO IN NUMBER)
IS
CURSOR src
IS
SELECT *
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP"
WHERE "NEW_STG_SEQ" IS NULL
AND "INT_ID" <= 7000;
STG_INT_ID NUMBER;
BEGIN
FOR des IN src
LOOP
STG_INT_ID := STG_SEQ.NEXTVAL;
INSERT
INTO MEMBER_INTERACT_MYSQL_STG VALUES
(
DES.INT_MEMBER_ID,
STG_INT_ID,
des.int_source,
des.int_date,
des.int_type,
NULL,
DES.INT_ID
);
UPDATE_COPIED_MEMBER_INTERACT(STG_INT_ID, DES.INT_ID);
COMMIT;
END LOOP;
END;
create or replace PROCEDURE UPDATE_COPIED_MEMBER_INTERACT( STG_INT_ID IN NUMBER, MYSQL_INT_ID IN NUMBER)
IS
BEGIN
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP"
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = STG_INT_ID
WHERE "INT_ID" = MYSQL_INT_ID;
END;
In fact, there were one procedure to update both tables, but due the error I received I find it might be easier to eliminate the eror by separating the procedure into two.
The error I get is :
ORA-02047: cannot join the distributed transaction in progress
ORA-06512: at "JTI_HTP.UPDATE_COPIED_MEMBER_INTERACT", line 19
ORA-06512: at "JTI_HTP.COPY_MYSQL_MOB_INT_TO_STG", line 28
ORA-06512: at line 6
line 19 is where the second procedure is called. Which I suspected that something has to do with the MySQL table update.
UPDATE
I have updated my script based on #Maheswaran Ravisankar answer as follow:
CREATE OR REPLACE PROCEDURE COPY_MYSQL_MOB_INT_TO_STG_V3(
P_BATCH_NO IN NUMBER)
IS
BEGIN
INSERT INTO MEMBER_INTERACT_MYSQL_STG
SELECT "INT_MEMBER_ID",
STG_SEQ.NEXTVAL,
"INT_SOURCE",
"INT_DATE",
"INT_TYPE",
CURRENT_DATE,
"INT_ID"
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" des
WHERE "NEW_STG_SEQ" IS NULL;
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" =
(SELECT STG_INT_ID
FROM MEMBER_INTERACT_MYSQL_STG B
WHERE A."INT_ID" = B.STG_INT_ID
);
END;
However, I am getting error ORA-02070: database JTIPARTNER_HTP does not support subqueries in this context.
INSERT
INTO MEMBER_INTERACT_MYSQL_STG
SELECt
DES.INT_MEMBER_ID,
STG_SEQ.NEXTVAL,
des.int_source,
des.int_date,
des.int_type,
NULL,
DES.INT_ID
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" des
WHERE "NEW_STG_SEQ" IS NULL
/* RETURNING STG_INT_ID BULK COLLECT INTO SOME RECORD; --Needed if only processed in array!*/
And update like below,
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = (SELECT STG_INT_ID FROM MEMBER_INTERACT_MYSQL_STG B
WHERE A.INT_ID = B.INT_ID);
(OR)
FOR REC IN (SELECT STG_INT_ID,INT_ID FROM MEMBER_INTERACT_MYSQL_STG)
LOOP
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = REC.STG_INT_ID
WHERE A.INT_ID = REC.INT_ID;
END LOOP;

Error Code: 1062 Duplicate entry for key 'PRIMARY'

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);