Stored Procedure to create Insert statements in MySql? - mysql

I need a storedprocedure to get the records of a Table and return the value as Insert Statements for the
selected records.
For Instance, The stored procedure should have three Input parameters...
1- Table Name
2- Column Name
3- Column Value
If
1- Table Name = "EMP"
2- Column Name = "EMPID"
3- Column Value = "15"
Then the output should be, select all the values of EMP where EMPID is 15
Once the values are selected for above condition, the stored procedure must
return the script for inserting the selected values.
The purpose of this is to take backup of selected values. when the SP returns
a value {Insert statements}, c# will just write them to a .sql file.
I have no idea about writing this SP, any samples of code is appreicated.
Thanks..

You can do this with mysqldump:
mysqldump --no-create-info --skip-triggers
--where="$COLUMN_NAME='$COLUMN_VALUE'" --databases $DB --tables $TABLE_NAME

To expand on Anuya's answer (which is referenced from http://kedar.nitty-witty.com/blog/mysql-stored-procedure-to-generate-extract-insert-statement) btw...
First need some helper mysql functions:
/*
isNumeric - return 1/true if passed in string is numeric, false otherwise
Usage example: select isNumeric('2012-02-16'); => 0
*/
DROP FUNCTION IF EXISTS `bettermentdb`.`isNumeric`;
DELIMITER ;;
CREATE DEFINER=`betterment-web`#`localhost` FUNCTION `bettermentdb`.`isNumeric`(s varchar(255))
RETURNS TINYINT
DETERMINISTIC
BEGIN
SET #match ='^(([0-9+-.$]{1})|([+-]?[$]?[0-9]*(([.]{1}[0-9]*)|([.]?[0-9]+))))$';
RETURN IF(s regexp #match, 1, 0);
END;;
DELIMITER ;
/*
isNumeric - return an input wrapped in "'" if value is non-numeric, original otherwise.
Depends on isNumeric()
Usage example: select wrapNonNumeric(now()); => '2012-02-16'
select wrapNonNumeric(NULL); => NULL
select wrapNonNumeric(1); => 1
*/
DROP FUNCTION IF EXISTS `bettermentdb`.`wrapNonNumeric`;
DELIMITER ;;
CREATE DEFINER=`betterment-web`#`localhost` FUNCTION `bettermentdb`.`wrapNonNumeric`(s varchar(255))
RETURNS varchar(255)
DETERMINISTIC
BEGIN
RETURN IF(isNumeric(s), s, concat("'", s, "'"));
END;;
DELIMITER ;
Outputs to console with col names defines and non-numeric values wrapped in quotes, while restricting on a given row of input db.table:
DELIMITER ;;
DROP PROCEDURE IF EXISTS GenerateInsertSQL;
CREATE DEFINER=`root`#`localhost` PROCEDURE GenerateInsertSQL(IN in_db varchar(20), IN in_table varchar(32), IN in_row BIGINT)
READS SQL DATA
BEGIN
DECLARE nullableValues varchar(1000);
DECLARE colNames varchar(1000);
DECLARE insertStmnt varchar(2000);
SELECT group_concat(concat('IFNULL(wrapNonNumeric(`',column_name,'`), "NULL")')) INTO #nullableValues from information_schema.columns where table_schema=in_db and table_name=in_table;
SELECT group_concat(concat('`',column_name,'`')) INTO #colNames from information_schema.columns where table_schema=in_db and table_name=in_table;
SET #insertStmnt=concat("select concat('INSERT INTO `", in_db, "`.`", in_table, "`(", #colNames, ") VALUES (', concat_ws(', ',",#nullableValues,"),');') from ", in_db, ".", in_table, " where id = ", in_row, " group by ", #colNames, ";");
PREPARE insertStmnt FROM #insertStmnt;
EXECUTE insertStmnt;
END
DELIMITER ;

DELIMITER $$
DROP PROCEDURE IF EXISTS `sample`.`InsGen` $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `InsGen`(
in_db varchar(20),
in_table varchar(20),
in_ColumnName varchar(20),
in_ColumnValue varchar(20)
)
BEGIN
declare Whrs varchar(500);
declare Sels varchar(500);
declare Inserts varchar(200);
declare tablename varchar(20);
declare ColName varchar(20);
set tablename=in_table;
# Comma separated column names - used for Select
select group_concat(concat('concat(\'"\',','ifnull(',column_name,','''')',',\'"\')'))
INTO #Sels from information_schema.columns where table_schema=in_db and table_name=tablename;
# Comma separated column names - used for Group By
select group_concat('`',column_name,'`')
INTO #Whrs from information_schema.columns where table_schema=in_db and table_name=tablename;
#Main Select Statement for fetching comma separated table values
set #Inserts=concat("select concat('insert IGNORE into ", in_db,".",tablename," values(',concat_ws(',',",#Sels,"),');')
as MyColumn from ", in_db,".",tablename, " where ", in_ColumnName, " = " , in_ColumnValue, " group by ",#Whrs, ";");
PREPARE Inserts FROM #Inserts;
EXECUTE Inserts;
END $$
DELIMITER ;

Had to deal with this issue today.
mysqldump is alright but not too friendly to change the WHERE clause.
I end up SQLyog, a MySQL client, it has a feature where you can export a result set of any sql SELECT statement into a bunch of INSERT statements.

Related

Looping through various tables MySQL [duplicate]

This question already has answers here:
MySQL loop through tables
(4 answers)
Closed 2 years ago.
I have a few similarly named tables in MySQL server (e.g: table_1; table_2; table_3 etc.). What I want to do is loop through these tables using a dynamic select query to insert the data into another table, let's say summary_table. Usually what I would do in Python if I create a connection to MySQL server:
for i in range(1,10):
insert = 'Insert into summary_table(*some column names*)'
insert += 'Select (*similar column names*) from table_' + str(i) + ';'
However, I'm not very familiar with the declare and syntax in MySQL server. I tried using this:
drop procedure if exists insert_loop;
delimiter //
create procedure insert_loop()
deterministic
begin
declare i int default 1;
declare tablename varchar(50);
set tablename := concat('table_',i);
while i <= 10 do
insert into summary_table(*some column names*)
select *some column names* from tablename;
set i = i+1;
end while;
end //
delimiter ;
call insert_loop;
But the error returns as schema_name.tablename doesn't exist.
For more information, I'm using MySQL community server version 8.0.23 at the moment for my learning purpose. Any feedback or help how I can solve this error with MySQL is appreciated. Thank you.
you can use EXECUTE command:
drop procedure if exists insert_loop;
delimiter //
create procedure insert_loop()
deterministic
begin
declare i int default 1;
declare tablename varchar(50);
set tablename := concat('table_',i);
while i <= 3 do
set tablename := concat('table_',i);
SET #query = concat('insert into summary_table (id, name, phone) select id, name , phone from ', tablename);
SET #result = NULL;
PREPARE stmt1 FROM #query;
EXECUTE stmt1;
set i = i+1;
end while;
end //
delimiter ;
call insert_loop;

How to set MySQL parameter multiple values in variable

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;

Mysql - procedure to get next auto increment

I'm having some problems writing a stored procedure to get next value of Auto Incremented column. I want to be able to pass a table name and have the value returned to a specified variable.
The procedure is as follows:
CREATE PROCEDURE Find_last_AI(
IN table_name VARCHAR(255),
OUT last_AI INT)
BEGIN
SELECT AUTO_INCREMENT
INTO last_AI
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'MySchema'
AND TABLE_NAME = table_name
LIMIT 1;
END;
The problem is, after I call the function like this:
CALL Find_last_AI('MyTable', #out);
SELECT #out;
I get the same wrong result - a numeric value (5) no matter what the table input is. The thing is, when I execute the code as a query the results yield correct values.
SELECT AUTO_INCREMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'MySchema'
AND TABLE_NAME = 'table_name'
LIMIT 1;
It seems that I'm forgetting something in the procedure itself, but I can't see it ?
I tried myself like below and it worked fine.
set #tabname = 'tab';
SELECT AUTO_INCREMENT
INTO #incre
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #tabname
LIMIT 1;
select #incre;
Also Good to mention that, using the query above you will get the next (future) auto_increment value (nothing but, present value + 1).
EDIT:
Finally got it; problem is with LIMIT 1 in your query. Try the below code and it's guaranteed to work fine (TESTED). Also, don't use any reserved word as variable name.
DELIMITER $$
CREATE PROCEDURE Find_last_AI(IN tname VARCHAR(255), OUT last_AI INT)
BEGIN
SELECT AUTO_INCREMENT
INTO last_AI
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'test'
AND TABLE_NAME = tname;
END$$
DELIMITER ;
Run the procedure like
CALL Find_last_AI('test3', #last_AI);
SELECT #last_AI;
to add the value auto_increment you must do it within the procedure, getting the last id and add 1, is a somewhat valid solution I leave SP:
#SP
DELIMITER $$
CREATE OR REPLACE PROCEDURE set_Estados(in Estado VARCHAR(45))
BEGIN
DECLARE validar INT;
DECLARE ID INT;
SELECT COUNT(*) INTO validar FROM table_name WHERE table_row=Estado;
if validar = 0 THEN
SELECT (max(estados_id)+1) INTO ID FROM table_name limit 1;
#the value estados_id its a auto_increment value, just call to add the value...
INSERT INTO table_name(estados_id,estados_estado) VALUES(ID,Estado);
CALL get_Estados(); #SP that show all data...
ELSE
SELECT CONCAT('El Estado: ',Estado,' ya existe.') ESTADO;
END IF;
END$$
DELIMITER ;
CALL set_Estados('Activo');

check if column exists before ALTER TABLE -- mysql

Is there a way to check if a column exists in a mySQL DB prior to (or as) the ALTER TABLE ADD coumn_name statement runs? Sort of an IF column DOES NOT EXIST ALTER TABLE thing.
I've tried ALTER IGNORE TABLE my_table ADD my_column but this still throws the error if the column I'm adding already exists.
EDIT: use case is to upgrade a table in an already installed web app-- so to keep things simple, I want to make sure the columns I need exist, and if they don't, add them using ALTER TABLE
Since mysql control statements (e.g. "IF") only work in stored procedures, a temporary one can be created and executed:
DROP PROCEDURE IF EXISTS add_version_to_actor;
DELIMITER $$
CREATE DEFINER=CURRENT_USER PROCEDURE add_version_to_actor ( )
BEGIN
DECLARE colName TEXT;
SELECT column_name INTO colName
FROM information_schema.columns
WHERE table_schema = 'connjur'
AND table_name = 'actor'
AND column_name = 'version';
IF colName is null THEN
ALTER TABLE actor ADD version TINYINT NOT NULL DEFAULT '1' COMMENT 'code version of actor when stored';
END IF;
END$$
DELIMITER ;
CALL add_version_to_actor;
DROP PROCEDURE add_version_to_actor;
Do you think you can try this?:
SELECT IFNULL(column_name, '') INTO #colName
FROM information_schema.columns
WHERE table_name = 'my_table'
AND column_name = 'my_column';
IF #colName = '' THEN
-- ALTER COMMAND GOES HERE --
END IF;
It's no one-liner, but can you at least see if it will work for you? At least while waiting for a better solution..
Utility functions and procedures
First, I have a set of utility functions and procedures that I use to do things like drop foreign keys, normal keys and columns. I just leave them in the database so I can use them as needed.
Here they are.
delimiter $$
create function column_exists(ptable text, pcolumn text)
returns bool
reads sql data
begin
declare result bool;
select
count(*)
into
result
from
information_schema.columns
where
`table_schema` = 'my_database' and
`table_name` = ptable and
`column_name` = pcolumn;
return result;
end $$
create function constraint_exists(ptable text, pconstraint text)
returns bool
reads sql data
begin
declare result bool;
select
count(*)
into
result
from
information_schema.table_constraints
where
`constraint_schema` = 'my_database' and
`table_schema` = 'my_database' and
`table_name` = ptable and
`constraint_name` = pconstraint;
return result;
end $$
create procedure drop_fk_if_exists(ptable text, pconstraint text)
begin
if constraint_exists(ptable, pconstraint) then
set #stat = concat('alter table ', ptable, ' drop foreign key ', pconstraint);
prepare pstat from #stat;
execute pstat;
end if;
end $$
create procedure drop_key_if_exists(ptable text, pconstraint text)
begin
if constraint_exists(ptable, pconstraint) then
set #stat = concat('alter table ', ptable, ' drop key ', pconstraint);
prepare pstat from #stat;
execute pstat;
end if;
end $$
create procedure drop_column_if_exists(ptable text, pcolumn text)
begin
if column_exists(ptable, pcolumn) then
set #stat = concat('alter table ', ptable, ' drop column ', pcolumn);
prepare pstat from #stat;
execute pstat;
end if;
end $$
delimiter ;
Dropping constraints and columns using the utilities above
With those in place, it is pretty easy to use them to check columns and constraints for existence:
-- Drop service.component_id
call drop_fk_if_exists('service', 'fk_service_1');
call drop_key_if_exists('service', 'component_id');
call drop_column_if_exists('service', 'component_id');
-- Drop commit.component_id
call drop_fk_if_exists('commit', 'commit_ibfk_1');
call drop_key_if_exists('commit', 'commit_idx1');
call drop_column_if_exists('commit', 'component_id');
-- Drop component.application_id
call drop_fk_if_exists('component', 'fk_component_1');
call drop_key_if_exists('component', 'application_id');
call drop_column_if_exists('component', 'application_id');
Make a count sentence with the example below by John Watson.
SELECT count(*) FROM information_schema.COLUMNS
WHERE COLUMN_NAME = '...'
and TABLE_NAME = '...'
and TABLE_SCHEMA = '...'
Save that result in an integer and then make it a condition to apply the ADD COLUMN sentence.
You can test if a column exists with:
IF EXISTS (
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME = '...'
and TABLE_NAME = '...'
and TABLE_SCHEMA = '...')
...
Just fill in your column name, table name, and database name.
Although its quite an old post but still i feel good about sharing my solution to this issue. If column doesn't exist then an exception would occur definitely and then i am creating the column in table.
I just used the code below:
try
{
DATABASE_QUERY="SELECT gender from USER;";
db.rawQuery(DATABASE_QUERY, null);
}
catch (Exception e)
{
e.printStackTrace();
DATABASE_UPGRADE="alter table USER ADD COLUMN gender VARCHAR(10) DEFAULT 0;";
db.execSQL(DATABASE_UPGRADE);
}
You can create a procedure with a CONTINUE handler in case the column exists (please note this code doesn't work in PHPMyAdmin):
DROP PROCEDURE IF EXISTS foo;
CREATE PROCEDURE foo() BEGIN
DECLARE CONTINUE HANDLER FOR 1060 BEGIN END;
ALTER TABLE `tableName` ADD `columnName` int(10) NULL AFTER `otherColumn`;
END;
CALL foo();
DROP PROCEDURE foo;
This code should not raise any error in case the column already exists. It will just do nothing and carry on executing the rest of the SQL.
DELIMITER $$
DROP PROCEDURE IF EXISTS `addcol` $$
CREATE DEFINER=`admin`#`localhost` PROCEDURE `addcol`(tbn varchar(45), cn varchar(45), ct varchar(45))
BEGIN
#tbn: table name, cn: column name, ct: column type
DECLARE CONTINUE HANDLER FOR 1060 BEGIN END;
set cn = REPLACE(cn, ' ','_');
set #a = '';
set #a = CONCAT("ALTER TABLE `", tbn ,"` ADD column `", cn ,"` ", ct);
PREPARE stmt FROM #a;
EXECUTE stmt;
END $$
DELIMITER ;
This syntax work for me :
SHOW COLUMNS FROM < tablename > LIKE '< columnName >'
More in this post :
https://mzulkamal.com/blog/mysql-5-7-check-if-column-exist?viewmode=0
As per MYSQL Community:
IGNORE is a MySQL extension to standard SQL. It controls how ALTER TABLE works if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, only one row is used of rows with duplicates on a unique key. The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.
So a working Code is:
ALTER IGNORE TABLE CLIENTS ADD CLIENT_NOTES TEXT DEFAULT NULL;
Data posted here:
http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

Mysql stored procedure don't take table name as parameter

I've written a stored procedure. It's working fine except taking the table name as input parameter.
Let see my proc in MySQL:
DELIMITER $$
USE `db_test`$$
DROP PROCEDURE IF EXISTS test_proc$$
CREATE DEFINER=`root`#`localhost`
PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100))
BEGIN
SELECT COUNT(*) FROM newsInfoTable WHERE newsServiceName=serviceName;
END$$
DELIMITER ;
Stored procedure calling parameters:
USE db_test;
CALL test_proc('abc','tbl_test_news');
Here the service name parameter is working fine. But if I include the newsInfoTable variable as table input parameter then a error shows.
Table 'db_test.newsinfotable' doesn't exist
Why does this happen only for table parameter? How can I retrieve from this error or
How I pass a table name into a stored procedure as a parameter?
An SP cannot be optimized with a dynamic table name, so many DBs, MySQL included, don't allow table names to be specified dynamically.
One way around this is to use Dynamic SQL.
CREATE DEFINER=`root`#`localhost` PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100))
BEGIN
SET #sql = CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=?;');
PREPARE s1 from #sql;
SET #paramA = serviceName;
EXECUTE s1 USING #paramA;
END$$
You can use EXECUTE IMMEDIATE for a "less is more" solution (for me, less code = good)
CREATE PROCEDURE test_proc(IN serviceName VARCHAR(10), IN newsInfoTable VARCHAR(100))
BEGIN
EXECUTE IMMEDIATE CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=''', serviceName, '''');
END
that part of a query cannot be dynamic.
you may consider implementing as a string that is executed dynamically at runtime
Although may not be what you want, alternatively, can consider to use conditionally if and prepare the statement.
DELIMITER $$
CREATE PROCEDURE select_count(IN table_name VARCHAR(20))
BEGIN
IF table_name = 'xxx' THEN
SELECT * FROM xxx;
ELSEIF table_name = 'yyy' THEN
...
ENDIF
END$$