How to set MySQL parameter multiple values in variable - mysql

I'm trying to assign multiple values in a variable and execute a query using it. For example below:
SET #ledger = "'Cash','Special Offer'";
SELECT `_ledger` FROM `acc_ledger` WHERE `_ledger` IN(#ledger);
But this doesn't work as planned. Is there a way to define multiple values in a variable? If yes, how? If no, can I have a suggestion on how to tackle this issue?

You can pass multiple values with comma separated and then split those variables int table and perform a join
create function to split comma separated parameter
DELIMITER $$
DROP FUNCTION IF EXISTS `SPLIT_STR` $$
CREATE FUNCTION SPLIT_STR(id_list VARCHAR(500), delimeter VARCHAR(10), position INT)
RETURNS VARCHAR(10)
DETERMINISTIC
BEGIN
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(id_list, delimeter, position),
LENGTH(SUBSTRING_INDEX(id_list, delimeter, position - 1)) + 1),
delimeter, '');
END$$
DELIMITER ;
call SPLIT_STR function from query
SET #ledger = "Cash,Special Offer";
CREATE TEMPORARY TABLE IF NOT EXISTS `selected_types` (type varchar(50));
#inserting splitted values to temp table
simple_loop: LOOP
SET indx=indx+1;
SET str=SPLIT_STR(x_id_list,',',indx);
IF str='' THEN
LEAVE simple_loop;
END IF;
INSERT INTO selected_types VALUES(str);
END LOOP simple_loop;
#filter with temp table
SELECT `_ledger` FROM
`acc_ledger` led
inner join selected_types tmp on tmp.type = led._ledger;

Related

Trouble with calling a stored procedure within an stored procedure and setting result as a variable

I'm trying to call a stored procedure from another stored procedure and store the value in a variable. The inner stored procedure basically checks if something exists and uses a select statement to return a zero or one. I keep getting an error. In this situation, MySQL is saying "=" is not valid at this position, expecting ";"
CREATE PROCEDURE `CardNames_Add` (searchedCard VARCHAR(50))
BEGIN
DECLARE exist TINYINT;
EXECUTE exist = CardNames_CheckExist searchedCard
IF (exist = 0)
INSERT INTO card_names (name)
VALUE(searchedCard)
END
You have to rewrite you other stored procedure, that you don't need btw, to give back a result
CREATE PROCEDURE CardNames_CheckExist (IN searchedCard VARCHAR(50), OUT result TINYINT )
BEGIN
--do some stuzff
result = 1
END
CREATE PROCEDURE `CardNames_Add` (searchedCard VARCHAR(50))
BEGIN
CALL CardNames_CheckExist(searchedCard,#result);
IF (#result = 0) THEN
INSERT INTO card_names (name)
VALUES (searchedCard);
END IF;
END

MySQL: How do a i insert a specific number of blank rows into a table

I want to grab a variable (between 1-365) and use this value to create the number of empty rows in a table:
insert into tblCustomer (ID) values (), (), ();
is there an easier way to do this or is using a loop the best way?
Any help would be appreciated.
A procedure with an IN parameter is quite easy
DELIMITER $$
DROP PROCEDURE IF EXISTS test_loop$$
CREATE PROCEDURE test_loop(IN number INT)
BEGIN
DECLARE x INT(11);
SET x = 1;
WHILE x <= number DO
INSERT INTO tblCustomer(id) VALUES('');
SET x = x + 1;
END WHILE;
END$$
DELIMITER ;
How to use it
CALL test_loop(20);

Generic logging with differences using triggers

I am trying to write a trigger that would simplify logging changes when a record is updated. I have a stored procedure that does an INSERT to a logging table called log_update and a trigger that does the job for 1 field:
DROP TRIGGER IF EXISTS `parents_update`;
DELIMITER $$
CREATE TRIGGER `parents_update` AFTER UPDATE ON `parents`
FOR EACH ROW
BEGIN
IF ( NEW.motherLastName != OLD.motherLastName ) THEN
CALL log_update( 'parent', NEW.id, 4, CONCAT( OLD.motherLastName, ' > ', NEW.motherLastName ) );
END IF;
END;
$$
DELIMITER ;
Is it a way to make this more generic like provide list of fields:
( 'motherFirstName', 'motherLastName', 'fatherFistName', .... )
and loop through this list with a parameter for the single IF statement?
Edit:
I come up with such loop:
DROP TRIGGER IF EXISTS `parents_update`;
DELIMITER $$
CREATE TRIGGER `parents_update` AFTER UPDATE ON `parents`
FOR EACH ROW
BEGIN
DECLARE _fieldName VARCHAR(25);
DECLARE done INT DEFAULT FALSE;
DECLARE fieldsCursor CURSOR FOR SELECT fieldName FROM log_fields WHERE tableName = 'parents';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN fieldsCursor;
the_loop : LOOP
FETCH fieldsCursor INTO _fieldName;
IF done THEN
LEAVE the_loop;
END IF;
-- _fieldName will contain values such 'motherLastName'
IF ( NEW ( _fieldName ) != OLD ( _fieldName ) ) THEN
CALL log_update( 'parent', NEW.id, 4, CONCAT( OLD ( _fieldName ), ' > ', NEW ( _fieldName ) ) );
END IF;
END LOOP the_loop;
CLOSE fieldCursor;
END;
$$
DELIMITER ;
where table log_fields will contain fields to check. Now I am facing the problem of how to access the NEW. or OLD. property if the field name is in a variable.
I would say you can use prepared statements to achieve it, but unfortunately it is not supported in triggers.
You can read more about it here: http://dev.mysql.com/doc/refman/5.1/en/stored-program-restrictions.html OR answer here: Alternative to using Prepared Statement in Trigger with MySQL
which mean you can't create dynamic SQL query in your trigger the same applied to NEW. or OLD. variables dinamic build, so the only way is create separate triggers for each table with listed all column names one by one

MySQL stored procedure insert multiple rows from list

How can I write a MySQL stored procedure to insert values from a variable sized list? More specifically I need to insert data into one parent table, get the ID from the insert, and then insert a variable number of child records along with the new ID into another table in a one-to-many relationship. My schema looks something like this:
TableA:
table_a_id -- Auto Increment
counter
some_data...
TableB:
table_b_id -- Auto Increment
table_a_id -- Foreign Key Constraint
some_data_from_list...
My stored procedure so far looks like this:
DELIMITER ;;
CREATE PROCEDURE insert_group_alert(
IN _some_data_a VARCHAR(255),
IN _data_list_b TEXT,
)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
END;
START TRANSACTION;
INSERT INTO TableA (
some_data,
counter
)
VALUES (
_some_data_a,
1
)
ON DUPLICATE KEY UPDATE
counter = counter + 1;
SELECT last_insert_id()
INTO #newId;
LIST INSERT ???:
INSERT INTO TableB (
table_a_id, some_data
) VALUES (
#newId,
list_item,
);
END LIST INSERT ???
COMMIT;
END ;;
DELIMITER ;
My thought was to pass in a list of items to insert into table B via a comma delimited string. The values are strings. I am not sure what to do in the LIST INSERT section. Do I need a loop of some sort? Is this stored procedure I have so far the correct way to do this? I don't want to do a batch as I could potentially have hundreds or even thousands of items in the list. Is there a better solution? I am using straight JDBC.
Yes, you need a loop, in which you can use substring_index() to get the values within the list. The solution is based on the answers from this SO topic:
DELIMITER ;;
CREATE PROCEDURE insert_group_alert(
IN _some_data_a VARCHAR(255),
IN _data_list_b TEXT,
)
BEGIN
DECLARE strLen INT DEFAULT 0;
DECLARE SubStrLen INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
END;
START TRANSACTION;
INSERT INTO TableA (
some_data,
counter
)
VALUES (
_some_data_a,
1
) -- you do not really need this, since you do not provide an id
ON DUPLICATE KEY UPDATE
counter = counter + 1;
SELECT last_insert_id()
INTO #newId;
do_this:
LOOP
SET strLen = CHAR_LENGTH(_data_list_b);
INSERT INTO TableB (table_a_id, some_data) VALUES(#newId,SUBSTRING_INDEX(_data_list_b, ',', 1));
SET SubStrLen = CHAR_LENGTH(SUBSTRING_INDEX(_data_list_b, ',', 1))+2;
SET _data_list_b = MID(_data_list_b, SubStrLen, strLen); --cut the 1st list item out
IF _data_list_b = '' THEN
LEAVE do_this;
END IF;
END LOOP do_this;
COMMIT;
END ;;
DELIMITER ;

MySQL CSV Row to multiple Rows

I need to migrate an old database to my new one. Unfortunately the guy who wrote the old database created an n,n relation using a field with comma separated foreign keys.
I would like to write a mysql query (maybe using insert into ... select) that splits those comma seperated foreign keys so that i can build a table where each row is a foreign key.
Is this possible?
It's not straightforward to do this in pure SQL. It will be easiest to retrieve each record in turn using a programming language of your choice and insert the many-to-many join table records based on the comma separated field. The following pseudo code suggests an approach that you might use:
for each (id, csv_foreign_keys) in source_rows do
foreign_keys = split ',', csv_foreign_keys
for each fk in foreign_keys do
insert (id, fk) into many-to-many link table
Once you've done this, the existing column holding the comma separated foreign keys can be removed.
My solution
DELIMITER $$
DROP FUNCTION IF EXISTS SPLITCVS $$
DROP PROCEDURE IF EXISTS MIGRATE $$
CREATE FUNCTION SPLITCVS (
x VARCHAR(255),
delim VARCHAR(12),
pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
delim, '') $$
CREATE PROCEDURE MIGRATE ()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE id INT(11);
DECLARE csv BLOB;
DECLARE cur CURSOR FOR SELECT uid,foreigns FROM old;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
FETCH cur INTO id, csv;
IF done THEN
LEAVE read_loop;
END IF;
IF LENGTH(csv) <> 0 THEN
SET #i = 0;
SET #seps = LENGTH(csv) - LENGTH(REPLACE(csv, ',', ''));
IF RIGHT(csv,1) <> ',' THEN
SET #seps = #seps + 1;
END IF;
WHILE #i < #seps DO
SET #i = #i + 1;
INSERT INTO db.newtable(uid_local,uid_foreign)
VALUES (id,SPLITCVS(csv,',',#i));
END WHILE;
END IF;
END LOOP;
CLOSE cur;
END $$
CALL MIGRATE() $$
DROP FUNCTION SPLITCVS $$
DROP PROCEDURE MIGRATE $$