Mysql - use query results for another query - mysql

I want to find some specific Columns of a database from Information_schema.Columns and edit those columns type. I don't know how can I use the result of my first query from Information_schema for making another query to edit columns.
Also I have to do it in MySQL, not PHP.
I've read about Procedures a little , but it was confusing. Acutally I've never done much with mysql.
I would really appreciate if anyone can show me the path or any tutorial.
thanks in advance

this could be what you are looking for. dynamic alter query:
SELECT CONCAT('ALTER TABLE `my_table` ',
GROUP_CONCAT(' CHANGE COLUMN `', COLUMN_NAME , '` ',
' `', COLUMN_NAME , '` DECIMAL (14,4)'))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'my_db' AND TABLE_NAME = 'my_table'
INTO #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
you can use a cursor in stored procedure to apply this to all tables.
DECLARE curs CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'my_db';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
OPEN curs;
SET bDone = 0;
REPEAT
FETCH curs INTO table_name;
IF table_name
/*alter query*/
END IF;
UNTIL bDone END REPEAT;
CLOSE curs;

Related

Extract data from multiple tables (mysql)

My problem: I have a few tables in mysql database with column "URL". I want to extract all of URLs to text file or another table.
Is it good way to go?
DELIMITER $$
CREATE or replace PROCEDURE link()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE tablename varchar(1000) DEFAULT "";
DECLARE link_tables
CURSOR for
SELECT table_name FROM information_schema.columns WHERE table_name like '__baza%' and COLUMN_NAME like 'url';
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET finished = 1;
OPEN link_tables;
getTable: LOOP
fetch link_tables into tablename;
IF finished = 1 THEN s
LEAVE getTable;
END IF;
select url from tablename into ... <<<< is it good idea? what to do next?
END LOOP getTable;
close link_tables;
END$$
DELIMITER ;
CALL link();
CREATE PROCEDURE link_urls (prefix VARCHAR(64))
BEGIN
SELECT GROUP_CONCAT( CONCAT( 'SELECT url FROM ', table_name) SEPARATOR ' UNION ')
INTO #sql
FROM information_schema.columns
WHERE table_name like CONCAT(prefix, '%');
SET #sql = CONCAT( 'CREATE TABLE urls ', #sql );
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
fiddle

Error Code: 1111. Invalid use of group function inside of a stored procedure to create triggers automatically

I'm trying to create a stored procedure that would create triggers automatically for all the tables that exist in my Database.
I came up with the following code but I got this error when I run it:
Error Code: 1111. Invalid use of group function
DELIMITER $$
DROP PROCEDURE IF EXISTS procCountAllTables $$
CREATE PROCEDURE procCountAllTables()
BEGIN
DECLARE table_name VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
# DECLARE column_name VARCHAR(255);
DECLARE cur CURSOR FOR
SELECT t.table_name
FROM information_schema.tables t
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name;
IF end_of_tables = 1 THEN
LEAVE tables_loop;
END IF;
# SET #s = CONCAT('SELECT ''', table_name, ''', COUNT(*) AS Count FROM ' , table_name);
SET #s = CONCAT('DROP TRIGGER IF EXISTS auditemployees_insert;
CREATE TRIGGER audit',
table_name,
'_insert AFTER INSERT ON ',
table_name,
'
FOR EACH ROW
BEGIN
INSERT INTO ',
table_name,
'_trigger (',
GROUP_CONCAT(CONCAT('`', column_name, '`')
SEPARATOR ','),
') SELECT ',
GROUP_CONCAT(CONCAT('`', column_name, '`')
SEPARATOR ','),
' FROM ',
table_name,
' WHERE id = NEW.id;
END$$');
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
Any ideas how to correct my error?
Yo, please do try this one out, mate:
DELIMITER $$
DROP PROCEDURE IF EXISTS procCountAllTables $$
CREATE PROCEDURE procCountAllTables()
BEGIN
DECLARE table_name VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
-- DECLARE column_name VARCHAR(255);
DECLARE cur CURSOR FOR
SELECT t.table_name
FROM information_schema.tables t
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name;
IF end_of_tables = 1 THEN
LEAVE tables_loop;
END IF;
-- SET #s = CONCAT('SELECT ''', table_name, ''', COUNT(*) AS Count FROM ' , table_name);
SET #s = CONCAT(
'DELIMITER $$',
'DROP TRIGGER IF EXISTS auditemployees_insert; CREATE TRIGGER audit',
table_name,
'_insert AFTER INSERT ON ',
table_name,
'FOR EACH ROW BEGIN INSERT INTO ',
table_name,
'_trigger (',
"GROUP_CONCAT(CONCAT('`', column_name, '`') SEPARATOR ',')",
') SELECT ',
"GROUP_CONCAT(CONCAT('`', column_name, '`') SEPARATOR ',')",
' FROM ',
table_name,
"WHERE id = NEW.id;"
"END$$"
);
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
Notes:
This type/style of implementation is not really recommended, especially if you will put this into a production level of environment
This will provide output/expected outcome but can sacrifice maintainability due to improper implementation
I like the idea of making a trigger through a stored procedure, but somehow I am against it
The only error I can see is the proper usage of ' and "
Proper indentation helps, trust me
And the commented line(s), you know what to do with those
Anyway, cheers
You're missing a query and then trying to fit it into the construction of the trigger code string. For each table, you need to
SELECT GROUP_CONCAT(CONCAT('`', column_name, '`') SEPARATOR ',') INTO #columnsList FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = [the current table name]
;
You could also just join to INFORMATION_SCHEMA.COLUMNS (on table_schema and table_name) in your cursor query, and have two fields; table_name and columns_list.
Edit: Also, I am not sure how much prepared statements accept multiple statements; so you may want to prepare and execute the preliminary DROP of each trigger separately from it's (re)creation.
Also:
I am not sure what purpose you had in mind for the COUNT query.
You may want to filter table names ending in _trigger from your cursor.
Edit: Something like this... (untested, so I might have typos or other similar oversights)
DELIMITER $$
DROP PROCEDURE IF EXISTS procCountAllTables $$
CREATE PROCEDURE procCountAllTables()
BEGIN
DECLARE table_name VARCHAR(255);
DECLARE trigger_name VARCHAR(255);
DECLARE target_tablename VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
DECLARE column_names VARCHAR(1024);
-- Be aware of GROUP_CONCAT's configured length limitation
DECLARE cur CURSOR FOR
SELECT t.table_name
, GROUP_CONCAT(CONCAT("`",c.column_name,"`")) AS column_names
FROM information_schema.tables AS t
INNER JOIN information_schema.columns AS c
USING (table_schema, table_name)
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE'
GROUP BY t.table_name
;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name, column_names;
IF end_of_tables = 1 THEN
LEAVE tables_loop;
END IF;
SET target_tablename := CONCAT(table_name, '_trigger');
SET trigger_name := CONCAT('audit', table_name, '_insert');
SET #s := CONCAT("DROP TRIGGER IF EXISTS `", trigger_name, "`;");
PREPARE stmt FROM #s;
EXECUTE stmt;
SET #s := CONCAT(
"CREATE TRIGGER `", trigger_name, "` "
"AFTER INSERT ON `", table_name, "` "
"FOR EACH ROW "
"INSERT INTO `", target_tablename, "` (", column_names, ") "
"SELECT ", column_names, " "
"FROM `", table_name, "` "
"WHERE id = NEW.id "
";"
;
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
Note that I've removed the BEGIN and END from the trigger definition. Since the trigger itself executes only a single statement, I think they are not necessary; and in my limited experience with these specific kinds of tasks, a delimiter override (which was not actually done on the prepare statement) tends to confuse prepared statements.
Also, you can probably get away without even using a select in the trigger if the cursor is changed like so:
SELECT t.table_name
, GROUP_CONCAT(CONCAT("`", column_name, "`")) AS column_names
, GROUP_CONCAT(CONCAT("NEW.`", column_name, "`")) AS source_list
...
and the trigger insert changed like so:
...
"INSERT INTO `", target_tablename, "` (", column_names, ") "
"VALUES (", source_list, ") "
";"
of course, you'll need to fetch the source_list from the cursor into a source_list local variable.

How to drop all columns with the same name in MySQL [duplicate]

How I can run a command in phpMyAdmin which will drop all columns in a database that have the prefix test_.
To drop a column from a table, use the syntax:
alter table <tablename> drop column <columnname>
To find all the columns in a table in a database that start with test_, do the following:
select column_name
from INFORMATION_SCHEMA.columns
where table_name = <table_name> and
table_schema = <schema_name> and
left(column_name, 5) = 'test_' -- not using "like" because '_' is a wildcard char
If you were doing this manually, I would recommend running the following query and then pasting the results in to a mysql query interface:
select concat('alter table ', table_name, ' drop column ', column_name)
from INFORMATION_SCHEMA.columns
where table_name = <table_name> and
schema_name = <schema_name> and
left(column_name, 5) = 'test_'
You can do something similar in code, by running the query, returning the results and then running each row as a query.
If you actually want to drop the columns from your schema, you will need to generate the necessary SQL commands dynamically from MySQL's information schema tables. Whilst it is possible to do that within a MySQL stored procedure using SQL prepared statements, which I demonstrate below, you may well find it easier to implement/understand in your preferred development language (which you do not mention in your question):
DELIMITER ;;
CREATE PROCEDURE dropMatchingColumns(IN pattern VARCHAR(64))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR
SELECT CONCAT(
'ALTER TABLE `', REPLACE( TABLE_NAME, '`', '``'), '` ',
GROUP_CONCAT(
'DROP COLUMN `', REPLACE(COLUMN_NAME, '`', '``'), '`'
)
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE pattern AND TABLE_SCHEMA = DATABASE()
GROUP BY TABLE_NAME
;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO #sql;
IF done THEN
LEAVE read_loop;
END IF;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur;
END;;
DELIMITER ;
With this procedure defined, one need only CALL dropMatchingColumns('test\_%'); in order to drop all the columns prefixed with test_ from the current database.
If you have MySQl Workbench then you can delete multiple columns by simply do a mass selection and telling workbench to do a mass deletion of the selected columns
I would like to explain or simplify this answer for those like me who were having trouble with this.
I was having trouble dropping a column with the name 'seq' in all tables in my database 'demo'.
You can create a selection with the commands formatted for each table using something like this:
Select concat('alter table ', table_name, ' drop column ', 'seq;')
from (select table_name
from INFORMATION_SCHEMA.tables
where table_name = table_name and
table_schema = 'demo') as t
This creates the alter table command for each table in the 'demo' database.
You have to select the result, copy it, and paste it back into the query editor.
It's a two step process, but if you have to do this several times, save the commands in a text file to run again later.

Command to drop all columns in a database that have prefix test_ to run

How I can run a command in phpMyAdmin which will drop all columns in a database that have the prefix test_.
To drop a column from a table, use the syntax:
alter table <tablename> drop column <columnname>
To find all the columns in a table in a database that start with test_, do the following:
select column_name
from INFORMATION_SCHEMA.columns
where table_name = <table_name> and
table_schema = <schema_name> and
left(column_name, 5) = 'test_' -- not using "like" because '_' is a wildcard char
If you were doing this manually, I would recommend running the following query and then pasting the results in to a mysql query interface:
select concat('alter table ', table_name, ' drop column ', column_name)
from INFORMATION_SCHEMA.columns
where table_name = <table_name> and
schema_name = <schema_name> and
left(column_name, 5) = 'test_'
You can do something similar in code, by running the query, returning the results and then running each row as a query.
If you actually want to drop the columns from your schema, you will need to generate the necessary SQL commands dynamically from MySQL's information schema tables. Whilst it is possible to do that within a MySQL stored procedure using SQL prepared statements, which I demonstrate below, you may well find it easier to implement/understand in your preferred development language (which you do not mention in your question):
DELIMITER ;;
CREATE PROCEDURE dropMatchingColumns(IN pattern VARCHAR(64))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR
SELECT CONCAT(
'ALTER TABLE `', REPLACE( TABLE_NAME, '`', '``'), '` ',
GROUP_CONCAT(
'DROP COLUMN `', REPLACE(COLUMN_NAME, '`', '``'), '`'
)
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE pattern AND TABLE_SCHEMA = DATABASE()
GROUP BY TABLE_NAME
;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO #sql;
IF done THEN
LEAVE read_loop;
END IF;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur;
END;;
DELIMITER ;
With this procedure defined, one need only CALL dropMatchingColumns('test\_%'); in order to drop all the columns prefixed with test_ from the current database.
If you have MySQl Workbench then you can delete multiple columns by simply do a mass selection and telling workbench to do a mass deletion of the selected columns
I would like to explain or simplify this answer for those like me who were having trouble with this.
I was having trouble dropping a column with the name 'seq' in all tables in my database 'demo'.
You can create a selection with the commands formatted for each table using something like this:
Select concat('alter table ', table_name, ' drop column ', 'seq;')
from (select table_name
from INFORMATION_SCHEMA.tables
where table_name = table_name and
table_schema = 'demo') as t
This creates the alter table command for each table in the 'demo' database.
You have to select the result, copy it, and paste it back into the query editor.
It's a two step process, but if you have to do this several times, save the commands in a text file to run again later.

SQL: deleting tables with prefix

How to delete my tables who all have the prefix myprefix_?
Note: need to execute it in phpMyAdmin
You cannot do it with just a single MySQL command, however you can use MySQL to construct the statement for you:
In the MySQL shell or through PHPMyAdmin, use the following query
SELECT CONCAT( 'DROP TABLE ', GROUP_CONCAT(table_name) , ';' )
AS statement FROM information_schema.tables
WHERE table_name LIKE 'myprefix_%';
This will generate a DROP statement which you can than copy and execute to drop the tables.
EDIT: A disclaimer here - the statement generated above will drop all tables in all databases with that prefix. If you want to limit it to a specific database, modify the query to look like this and replace database_name with your own database_name:
SELECT CONCAT( 'DROP TABLE ', GROUP_CONCAT(table_name) , ';' )
AS statement FROM information_schema.tables
WHERE table_schema = 'database_name' AND table_name LIKE 'myprefix_%';
Some of the earlier answers were very good.
I have pulled together their ideas with some
notions from other answers on the web.
I needed to delete all tables starting with 'temp_'
After a few iterations I came up with this block of code:
-- Set up variable to delete ALL tables starting with 'temp_'
SET GROUP_CONCAT_MAX_LEN=10000;
SET #tbls = (SELECT GROUP_CONCAT(TABLE_NAME)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'my_database'
AND TABLE_NAME LIKE 'temp_%');
SET #delStmt = CONCAT('DROP TABLE ', #tbls);
-- SELECT #delStmt;
PREPARE stmt FROM #delStmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I hope this is useful to other MySQL/PHP programmers.
show tables like 'prefix_%';
copy the results and paste them into a text editor or output the query to a file, use a few search and replaces to remove unwanted formatting and replace \n with a comma
put a ; on the end and add drop table to the front.
you'll get something that looks like this:
drop table myprefix_1, myprefix_2, myprefix_3;
#andre-miller solution is good but there is even better and slightly more professional that will help you execute all in one go. Still will need more than one command but this solution will allow you to use the SQL for automated builds.
SET #tbls = (SELECT GROUP_CONCAT(TABLE_NAME)
FROM information_schema.TABLES
WHERE TABLE_NAME LIKE 'myprefix_%');
PREPARE stmt FROM 'DROP TABLE #tbls';
EXECUTE stmt USING #tbls;
DEALLOCATE PREPARE stmt;
Note: this code is platform dependant, it's for MySQL but for sure it could be implemented for Postgre, Oracle and MS SQL with slight changes.
SELECT CONCAT("DROP TABLE ", table_name, ";")
FROM information_schema.tables
WHERE table_schema = "DATABASE_NAME"
AND table_name LIKE "PREFIX_TABLE_NAME%";
I drop table successfully by edit query to like this
SET GROUP_CONCAT_MAX_LEN=10000;
SET FOREIGN_KEY_CHECKS = 0;
SET #tbls = (SELECT GROUP_CONCAT(CONCAT('`', TABLE_NAME, '`'))
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'pandora'
AND TABLE_NAME LIKE 'temp_%');
SET #delStmt = CONCAT('DROP TABLE ', #tbls);
-- SELECT #delStmt;
PREPARE stmt FROM #delStmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET FOREIGN_KEY_CHECKS = 1;
Just another solution using GROUP_CONCAT so it will execute one drop query like
DROP TABLE table1,table2,..
SET #Drop_Stm = CONCAT('DROP TABLE ', (
SELECT GROUP_CONCAT(TABLE_NAME) AS All_Tables FROM information_schema.tables
WHERE TABLE_NAME LIKE 'prefix_%' AND TABLE_SCHEMA = 'database_name'
));
PREPARE Stm FROM #Drop_Stm;
EXECUTE Stm;
DEALLOCATE PREPARE Stm;
You can do that in one command with MySQL:
drop table myprefix_1, myprefix_2, myprefix_3;
You'll probably have to build the table list dynamically in code though.
An alternative approach would be to use the general purpose routine library for MySQL 5.
I just wanted to post the exact SQL I used - it's something of a mixture of the top 3 answers:
SET GROUP_CONCAT_MAX_LEN=10000;
SET #del = (
SELECT CONCAT('DROP TABLE ', GROUP_CONCAT(TABLE_NAME), ';')
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'database_name'
AND TABLE_NAME LIKE 'prefix_%'
);
PREPARE stmt FROM #del;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I found that the prepared statements were a little tricky to get working for me but setting the GROUP_CONCAT_MAX_LEN was essential when you have a lot of tables. This resulted in a simple three-step process with cut-and paste from the mysql command line that worked great for me:
SET GROUP_CONCAT_MAX_LEN=10000;
SELECT CONCAT( 'DROP TABLE ', GROUP_CONCAT(table_name) , ';' )
AS statement FROM information_schema.tables
WHERE table_name LIKE 'myprefix_%';
Then carefully cut-and-paste the resulting long DROP statement.