This stored procedure is to search through all tables and columns in database.
DELIMITER $$
DROP PROCEDURE IF EXISTS get_table $$
CREATE
/*[DEFINER = { user | CURRENT_USER }]*/
PROCEDURE `auradoxdb`.`get_table`(in_search varchar(50))
READS SQL DATA
BEGIN
DECLARE trunc_cmd VARCHAR(50);
DECLARE search_string VARCHAR(250);
DECLARE db,tbl,clmn CHAR(50);
DECLARE done INT DEFAULT 0;
DECLARE COUNTER INT;
DECLARE table_cur CURSOR FOR
SELECT concat(SELECT COUNT(*) INTO #CNT_VALUE
FROM `’,table_schema,’`.`’, table_name,’`
WHERE `’, column_name,’` REGEXP ”’,in_search,”’
)
, table_schema
, table_name
, column_name
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA NOT IN (‘information_schema’,'test’,'mysql’);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
# #Truncating table for refill the data for new search.
PREPARE trunc_cmd FROM “TRUNCATE TABLE temp_details;”
EXECUTE trunc_cmd ;
OPEN table_cur;
table_loop:LOOP
FETCH table_cur INTO search_string,db,tbl,clmn;
# #Executing the search
SET #search_string = search_string;
SELECT search_string;
PREPARE search_string FROM #search_string;
EXECUTE search_string;
SET COUNTER = #CNT_VALUE;
SELECT COUNTER;
IF COUNTER>0 THEN
# # Inserting required results from search to tablehhh
INSERT INTO temp_details VALUES(db,tbl,clmn);
END IF;
IF done=1 THEN
LEAVE table_loop;
END IF;
END LOOP;
CLOSE table_cur;
# #Finally Show Results
SELECT * FROM temp_details;
END $$
DELIMITER ;
Following error occurs when execute this..
Error Code : 1064
You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near 'SELECT COUNT(*)
INTO #CNT_VALUE FROM `’,table_schema,’`.`’,table_name,’`' at line 12
(0 ms taken)
could any body please help me to solve this?
It appears that you are trying to dynamically build an SQL statement for each table. To do this, you will need to quote the text parts as if it was a normal string and concatenate the dynamic parts. Replacing the query with the following should work:
SELECT concat('SELECT COUNT(*) INTO #CNT_VALUE FROM ',
table_schema,'.', table_name,
' WHERE ', column_name,' REGEXP ''',in_search,''''
)
, table_schema
, table_name
, column_name
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA NOT IN ('information_schema','test','mysql');
Related
I want to alter my tables dynamically based on whether the table has specific column.
My database name is summer_cms, and there are over 50 tables in it.
What I want are below:
If a table has a column named add_time, then I would like to add a column add_user_id in it.
Similarly, I would like to add update_user_id in the table if update_time is found.
I know I should get it down in the process of creating the database schemas, but my database has been built and I have to alter it by need.
So I create a procedure to do it:
CREATE PROCEDURE ALTER_SUMMER_TABLE()
BEGIN
DECLARE tableName VARCHAR(64);
DECLARE exitence VARCHAR(64);
DECLARE ntable INT; # number of tables
DECLARE i INT; # index
SET i = 0;
# get the count of table
SELECT COUNT(DISTINCT(TABLE_NAME)) INTO ntable FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'summer_cms';
WHILE i < ntable DO
# select the specific table name into the variable of `tableName`.
SELECT TABLE_NAME INTO tableName
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND COLUMN_NAME = 'add_time'
LIMIT 1 OFFSET i;
# alter table, but I get error in this clause.
ALTER TABLE tableName ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 COMMENT 'add user id';
# check if the table has `update_time`
SELECT TABLE_NAME INTO exitence
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND TABLE_NAME = tableName
AND COLUMN_NAME = 'update_time';
# add `update_user_id` if `update_time` be found.
IF exitence THEN
ALTER TABLE tableName ADD COLUMN `update_user_id` INT NOT NULL DEFAULT 0 COMMENT 'update user id';
END IF;
SET i = i + 1;
END WHILE;
END
But I got an error when I call this procedure.
Procedure execution failed
1146 - Table 'summer_cms.tableName' doesn't exist
Dose anyone could tell me what I was missing or wrong? Any help will be appreciated.
There a a few alterations you can make to your procedure to make it more streamlined as well as getting round a few problems.
First using a cursor to select the table names rather than using the two selects your using. Secondly to use a prepared statement to allow you to dynamically set the table name...
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `ALTER_SUMMER_TABLE`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE tableName VARCHAR(64);
declare cur cursor for SELECT TABLE_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND COLUMN_NAME = 'add_time';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
open cur;
start_loop: loop
fetch cur into tableName;
if (done = 1 )THEN
LEAVE start_loop;
END IF;
SET #sql = CONCAT('ALTER TABLE ', tableName,' ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 ');
PREPARE stmt FROM #sql;
EXECUTE stmt;
end loop;
close cur;
END$$
DELIMITER ;
You could do a few tweaks - only fetch table names where the column doesn't already exist for example.
Here's an example of dynamic sql
drop procedure if exists alter_table;
delimiter //
CREATE DEFINER=`root`#`localhost` procedure alter_table()
begin
declare tablename varchar(20);
set tablename = 'u';
set #sqlstmt = concat('ALTER TABLE ', tableName, ' ADD COLUMN ', char(96), 'add_user_id', char(96), ' INT NOT NULL DEFAULT 0 COMMENT', char(39), 'add user id', char(39),';');
prepare stmt from #sqlstmt;
execute stmt;
deallocate prepare stmt;
end //
delimiter ;
Note I have used ascii backticks and single quotes.
I need to get the result table with there fields
- table_name, min_date, max_date
Here is my query, which I should execute for all tables
SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM testTable
GROUP BY short_date
HAVING COUNT(*) > 1) as Duplicates
Then I found out how to get all table names
I do it in this way
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
But I don't know how to execute it for all table and fill in the result in a new table.
I tried to do it in this way
DECLARE #DB_Name varchar(50)
DECLARE #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
But I got this error
Syntax error or access violation: 1064 You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near 'DECLARE #DB_Name varchar(50) DECLARE
#Command varchar(100)' at line 1
UPD
CREATE PROCEDURE GetData()
BEGIN
DECLARE #DB_Name varchar(50), #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%_') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END;
CLOSE database_cursor
DEALLOCATE database_cursor
END;
CALL GetData()
Add DELIMITER $$ at the start; add DELIMITER ; after END.
Get rid of declaring Command. Instead use #command, which does not need to be declared.
Add SELECT #command; after the SELECT #command := ...; so that we can do some debugging.
The CLOSE and DEALLOCATE statements need ; to terminate them.
Test for running out of rows to FETCH.
You really need to look at a number of examples of Stored procedures, especially those with cursors.
Update
Ugh, I did not spot even half the syntax errors. This might work (I can't tell because I don't have your particular tables or columns.):
DROP PROCEDURE IF EXISTS so42856538;
DELIMITER $$
CREATE PROCEDURE so42856538()
LANGUAGE SQL
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
DECLARE _TableName varchar(64);
DECLARE _done INT DEFAULT FALSE;
DECLARE database_cursor CURSOR FOR
SELECT TABLE_NAME
FROM `information_schema`.`TABLES`
WHERE `TABLE_SCHEMA` = 'test'
AND `TABLE_NAME` LIKE 'test%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _done = TRUE;
OPEN database_cursor;
curs_loop: LOOP
FETCH NEXT FROM database_cursor INTO _TableName;
IF _done THEN LEAVE curs_loop; END IF;
SET #Command := CONCAT(
'SELECT MIN(short_date) as FirstDuplicatedDate,
MAX(short_date) as LastDuplicatedDate
FROM ( SELECT short_date, type, value, count(*) as cnt
FROM ', _TableName, '
WHERE type = "test"
GROUP BY short_date, type, value
HAVING COUNT(*) > 1 ) as Duplicates'
);
SELECT _TableName, #command; -- Debugging (remove if it is clutter)
PREPARE _sql FROM #command;
EXECUTE _sql;
DEALLOCATE PREPARE _sql;
END LOOP;
CLOSE database_cursor;
END $$
DELIMITER ;
CALL so42856538;
right... you might want to try this.
remove this line and run the query again.
DECLARE #DB_Name varchar(50), #Command varchar(100);
i think in mysql you can just use a variable without declaring it and then cast when necessary.
As far as my knowledge concern this error is due to ,DELIMETER and one more thing that you have to apply cursor properly to iterate whole rowset.Here in below code i had wrote down procedure with CURSOR.Make dynamic query and execute that dynamic query using
PREPARE stmt FROM #VAR_QRY; EXECUTE stmt;
That dynamic query will returns exact output you want.Here i had assuming that you have basic knowledge about trigger,loop and Cursor
Try below code.
Hope this will helps.
DROP PROCEDURE IF EXISTS ITERATEALLTABLE;
DELIMITER $$
CREATE PROCEDURE ITERATEALLTABLE()
BEGIN
DECLARE VAR_TABLE varchar(100);
DECLARE VAR_QRY varchar(100);
DECLARE VAR_FINISHED INT(11) DEFAULT 0;
DECLARE DATABASE_CURSOR CURSOR FOR
SELECT name AS TableNames
FROM (
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
)Z ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET VAR_FINISHED = 1;
OPEN DATABASE_CURSOR;
GET_NEXTRECORD: LOOP
FETCH DATABASE_CURSOR INTO VAR_TABLE;
IF VAR_FINISHED = 1 THEN
LEAVE GET_NEXTRECORD;
END IF;
SET #VAR_QRY = CONCAT("SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM " , VAR_TABLE , " WHERE type = 'test'
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates");
PREPARE stmt FROM #VAR_QRY;
EXECUTE stmt;
END LOOP GET_NEXTRECORD;
CLOSE DATABASE_CURSOR;
END;
CALL ITERATEALLTABLE;
I need to rename column for all tables in my databse.
I could get list of columns using this query:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME= <Column Name>;
But how actually I could rename it as simple as possible and do not write
ALTER TABLE <Table Name >RENAME COLUMN <Old name> to <New Name>;
for each table.
I've tried to write a procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS renameColumn $$
CREATE PROCEDURE renameColumn(IN oldName tinytext, IN newName tinytext)
BEGIN
DECLARE #name VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE tableName_cursor CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME=oldName;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
OPEN tableName_cursor;
rename_loop: LOOP
FETCH tableName_cursor #name;
ALTER TABLE #name RENAME COLUMN oldName to newName;
IF exit_loop THEN
LEAVE rename_loop;
END IF;
END LOOP rename_loop;
END $$
DELIMITER;
But I have the following error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '#name VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE ta' at line 3
Could you please help me to resolve this issue
You can try this.
SELECT CONCAT(
'ALTER TABLE ', TABLE_NAME,
' RENAME COLUMN ', COLUMN_NAME,
' NEW_', COLUMN_NAME,
';') AS rename_script
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'your_db'
Try the following solution hope it will help
DECLARE #name VARCHAR(50) -- database name
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME= 'OldColumn';
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
set #name = #name + '.OldColumn'
EXEC sp_rename #name, 'NewColumn', 'COLUMN';
print(#name)
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor
I want find a number of UserId from all tables call searchUser(3,'UserId')
error: 0 14:30:14 call searchUser(3,'UserId') Error Code: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1
DELIMITER $$
CREATE PROCEDURE `searchUser`( in_search int(11),in_column_name varchar(50) )
READS SQL DATA
BEGIN
DECLARE trunc_cmd VARCHAR(50);
DECLARE searchUserId int (11);
DECLARE db,tbl,clmn CHAR(50);
DECLARE done INT DEFAULT 0;
DECLARE COUNTER INT;
DECLARE table_cur CURSOR FOR
SELECT concat('SELECT COUNT(*) INTO #CNT_VALUE FROM `',table_name,'` WHERE `', in_column_name,'` = "',in_search,'"') ,table_name,column_name FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = 'comments' and column_name=in_column_name ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
PREPARE trunc_cmd FROM "TRUNCATE TABLE temp_details;";
EXECUTE trunc_cmd ;
OPEN table_cur;
table_loop:LOOP
FETCH table_cur INTO db, tbl, clmn;
SET #searchUserId = searchUserId;
SELECT searchUserId;
PREPARE searchUserId FROM #searchUserId;
EXECUTE searchUserId;
SET COUNTER = #CNT_VALUE;
SELECT COUNTER;
IF COUNTER>0 THEN
INSERT INTO temp_details VALUES(db,tbl,clmn);
END IF;
IF done=1 THEN
LEAVE table_loop;
END IF;
END LOOP;
CLOSE table_cur;
SELECT * FROM temp_details;
END
Problem must be due to:
DECLARE searchUserId int (11);
and:
SET #searchUserId = searchUserId;
SELECT searchUserId;
PREPARE searchUserId FROM #searchUserId;
EXECUTE searchUserId;
I assume that you are thinking searchUserId has a value. But nowhere in the code you assigned a value to it. By default it is a NULL. And hence the statement EXECUTE searchUserId is translate to EXECUTE NULL. This caused the error you specified.
To resolve it, you should first assign a proper value to the searchUserId variable declared.
BTW, why are you using the same variable name searchUserId for a local variable, global variable, and statement alias? It would confuse the readers of the program and hence is not advised to practice.
I guess problem lies in this statement-creation-statement:
SELECT concat('SELECT COUNT(*) INTO #CNT_VALUE FROM `',table_name,'` WHERE `', in_column_name,'` = "',in_search,'"') ,table_name,column_name FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = 'comments' and column_name=in_column_name ;
Please execute the statement standalone and see what you get.
This is my stored procedure to search throgh all databases,tables and columns.
This procedure got created with out any error.
DELIMITER $$
DROP PROCEDURE IF EXISTS `mydb`.`get_table`$$
CREATE DEFINER=`root`#`%` PROCEDURE `get_table`(in_search varchar(50))
READS SQL DATA
BEGIN
DECLARE trunc_cmd VARCHAR(50);
DECLARE search_string VARCHAR(250);
DECLARE db,tbl,clmn CHAR(50);
DECLARE done INT DEFAULT 0;
DECLARE COUNTER INT;
DECLARE table_cur CURSOR FOR
SELECT concat('SELECT COUNT(*) INTO #CNT_VALUE FROM ',
table_schema,'.', table_name,
' WHERE ', column_name,' REGEXP ''',in_search,''''
)
,table_schema,table_name,column_name
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA NOT IN ('mydb','information_schema');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
# #Truncating table for refill the data for new search.
PREPARE trunc_cmd FROM 'TRUNCATE TABLE temp_details';
EXECUTE trunc_cmd ;
OPEN table_cur;
table_loop:LOOP
FETCH table_cur INTO search_string,db,tbl,clmn;
# #Executing the search
SET #search_string = search_string;
SELECT search_string;
PREPARE search_string FROM #search_string;
EXECUTE search_string;
SET COUNTER = #CNT_VALUE;
SELECT COUNTER;
IF COUNTER>0 THEN
# # Inserting required results from search to table
INSERT INTO temp_details VALUES(db,tbl,clmn);
END IF;
IF done=1 THEN
LEAVE table_loop;
END IF;
END LOOP;
CLOSE table_cur;
# #Finally Show Results
SELECT * FROM temp_details;
END$$
DELIMITER ;
But when calling this procedure following error occurs.
call get_table('aaa')
Error Code : 1064 You have an error in
your SQL syntax; check the manual that
corresponds to your MySQL server
version for the right syntax to use
near 'delete REGEXP 'aaa'' at line 1
(0 ms taken)
Where does "delete" come from? Do you have a column_name with that name? If so, use better names, not reserved ones, or use nasty backticks ` or ANSI-quotes " around the column name.
Constructions like this are vulnerable to SQL injection.