This is the sql i'm using based from this answer:
SET #pattern = '%_movielist';
SELECT concat('TRUNCATE TABLE ', GROUP_CONCAT(concat(TABLE_NAME)), ';')
INTO #truncatelike FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE #pattern;
SELECT #truncatelike;
PREPARE stmt FROM #truncatelike;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
but I get this error Access denied for user 'root'#'%' to database 'information_schema'.
What am I doing wrong? It seems to work for other users
You trying to execute this statement on "information_schema" database. Read more about this database [https://dev.mysql.com/doc/refman/5.7/en/information-schema.html]
You should not be running statements on the information_schema database (unless you REALLY know what you're doing). The database serves as a "meta" repository that dictates how the server operates. Chances are that you have no need to touch it and you'll likely brick your server if you do.
This is already answered here. [#1044 - Access denied for user 'root'#'localhost' to database 'information_schema'
Restriction to above: This query will work only if the no of table returned by the statement is 1 for more than 1 tables, you will require to use it in iteration.
To make this work for all the table matching the pattern we would require to use stored procedure.
Please change the Procedure name
CREATE PROCEDURE `new_procedure`()
BEGIN
-- Pattern to Match
SET #pattern = '%_movielist';
-- Temporary Table to Store the Result of The Select Statement
CREATE TEMPORARY TABLE IF NOT EXISTS Table_ToBeTruncated
(
Id int NOT NULL AUTO_INCREMENT,TableName varchar(100),
PRIMARY KEY (id)
);
-- Insert all the TableName to be Truncated
insert Table_ToBeTruncated(TableName)
SELECT distinct concat('TRUNCATE TABLE `', TABLE_NAME, '`;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE #pattern and TABLE_SCHEMA = 'movielist';
-- Declare a variable to count the no of records to be truncated.
SET #count=(Select count(*)from Table_ToBeTruncated);
-- Iterate the list
WHILE #count> 0 DO
-- Pick One table from the Temporary Table List;
SELECT TableName into #truncatelike from Table_ToBeTruncated where ID= #count;
-- Prepare the statement
PREPARE stmt FROM #truncatelike;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- Decrease the counter.
set #count = #count- 1;
END WHILE;
drop TEMPORARY TABLE IF EXISTS Table_ToBeTruncated ;
END
Related
I have a database named my_db.
Each table in my_db has a column set_id that has values from 2140 to 2180. I would like to go through all the tables in my_db and delete the rows where set_id is greater than 2170. How do I do that?
I think, that is not a query for that, but you can do something like this
SELECT CONCAT('delete from my_db.',table_name,' where set_id > 270') FROM information_schema.tables where table_schema='my_db';
the result of that are all the queries that you need to run. you can copy and run it.
I like Marco's answer since it's short and provides a nice workaround. This is what I've come up with using Procedures, While-Loops, and Prepared-Statements. No copying is needed.
It retrieves and stores the into a temporary table, then loops through each table-name and performs individual DELETE statements.
DROP PROCEDURE IF EXISTS myPurge;
-- Will be used to signify the end of the procedure
DELIMITER ;;
-- Use a procedure
CREATE PROCEDURE myPurge()
BEGIN
-- Retrieve tables from information_schema and
-- Store them into a temporary table
DROP TABLE IF EXISTS tempTables;
CREATE TEMPORARY TABLE tempTables
SELECT table_name FROM information_schema.tables WHERE table_schema = 'my_db';
-- Initialise variables
SET #i = 0;
SELECT COUNT(*) FROM tempTables INTO #n;
-- Loop from 0 to number of rows
WHILE #i < #n DO
-- Retrieve table from row #i
-- SELECT * FROM tempTables LIMIT #i, 1 INTO #atable; -- doesn't seem to work on MySQL v5
-- Prepare and execute a subsidiary query
SELECT CONCAT("SELECT * FROM tempTables LIMIT ", #i, ",1 INTO #atable") INTO #preLimStmt;
PREPARE limStmt FROM #preLimStmt;
EXECUTE limStmt;
-- Save statement into temporary variable
-- HERE we prepare your PURGE
SELECT CONCAT("DELETE FROM my_db.", #atable, " WHERE set_id > 2170") INTO #preStmt;
-- Prepare and execute the purge statement
PREPARE stmt FROM #preStmt;
EXECUTE stmt;
-- Increment #i
SET #i = #i + 1;
END WHILE;
END;;
-- Call the procedure
CALL myPurge();
-- cleanup
DEALLOCATE PREPARE limStmt;
DEALLOCATE PREPARE stmt;
-- Reset to default
DELIMITER ;
-- Remove the temporary table
DROP TABLE tempTables;
Note: I'm using MySQL version 5.7.23.
I am trying to create a database with some data not all. I don't need 1M+ records to do what I need so I am okay with only 10000 rows.
I figured I can use a stored procedure to loop through all the table and manually create each table and insert only 10000 rows.
I created a stored procedure like this
CREATE DEFINER=`root`#`10.%` PROCEDURE `createNewDatabase`(in db_name varchar(100), in new_db_name varchar(100))
BEGIN
DECLARE finish INT DEFAULT 0;
DECLARE tbl VARCHAR(100);
DECLARE cur_tables CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = db_name AND TABLE_TYPE='BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finish = 1;
OPEN cur_tables;
my_loop: LOOP
FETCH cur_tables INTO tbl;
IF finish = 1 THEN
LEAVE my_loop;
END IF;
SET #str = CONCAT('DROP TABLE IF EXISTS `', new_db_name, '`.`' , tbl , '`; CREATE TABLE `', new_db_name, '`.`' , tbl , '` LIKE `', db_name , '`.`', tbl,'`; INSERT INTO `', new_db_name , '`.`' , tbl, '` SELECT * FROM `', db_name ,'`.`', tbl , '` LIMIT 10000;');
PREPARE stmt FROM #str;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur_tables;
END
Then I called it like this
CALL createNewDatabase('baseTable', 'newTable');
But I run the procedure I get the following error
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CREATE TABLE `newTable`.`account_addresses` LIKE `baseTable`.`account_addres' at line 1
if I added the following 2 lines after just before the prepare statement
SELECT #str;
LEAVE my_loop;
I get the following queries which works if I executed them manually
DROP TABLE IF EXISTS `newTable`.`account_addresses`;
CREATE TABLE `newTable`.`account_addresses` LIKE `baseTable`.`account_addresses`;
INSERT INTO `newTable`.`account_addresses` SELECT * FROM `newTable`.`account_addresses` LIMIT 10000;
CREATE TABLE `newTable`.`account_addresses` LIKE `baseTable`.`account_addresses`; INSERT INTO `newTable`.`account_addresses` SELECT * FROM `baseTable`.`account_addresses` LIMIT 10000;
What am I doing wrong here? Why it is erroring?
Quote from mysql's documentation on PREPARE:
The text must represent a single statement, not multiple statements.
You are trying to execute a drop table and a create table statement, insert records in 1 prepared statement and this is not allowed. Have 3 separate prepared statement for the 3 commands.
I'm looking for a way to generate valid HTML code within MySQL (without PHP) by converting any query output into an HTML table.
Here's my progress so far and evidently, I'm stuck. I hope I can get some help, thanks.
1. "dynSQL" - A procedure to take any Select query and create a named table out of it
Since MySQL doesn't allow dynamic queries in functions, I'm calling a procedure that creates a named table, tmp. I can't use a temporary table because info about temporary tables is not available in information_schema (in mysql 5.6)
CREATE DEFINER=`root`#`%` PROCEDURE `dynSQL`(SQL_QUERY TEXT)
BEGIN
set #SQLQ := 'Drop table if exists tmp;';
PREPARE stmt from #SQLQ;
Execute stmt;
SET #SQLQ := concat('create table tmp as ',SQL_QUERY);
PREPARE stmt from #SQLQ;
Execute stmt;
-- I'm adding a auto increment ID column to be able to loop through the rows later
SET #SQLQ := "ALTER TABLE tmp add column CustColHTML_ID INT NOT NULL AUTO_INCREMENT FIRST, ADD primary KEY Id(CustColHTML_ID)";
PREPARE stmt from #SQLQ;
Execute stmt;
DEALLOCATE PREPARE stmt;
END
2. "MakeHTML" - Function to read from the table tmp and return a formatted HTML table
CREATE DEFINER=`root`#`%` FUNCTION `MakeHTML`() RETURNS text CHARSET utf8
DETERMINISTIC
BEGIN
DECLARE HTML text default "<TABLE><TR>";
DECLARE rowCount int default 0;
DECLARE i int default 0;
select concat('<TR>',group_concat('<TD>',column_name,'</TD>' separator ''),'</TR>') into html from information_Schema.`columns` where table_name='tmp';
Select max(CustColHTML_ID) into rowCount from `tmp`; -- Set the row counter
WHILE i<=rowCount DO
-- What do I do here? How do I loop through the columns of table tmp?
set i:=i+1;
END WHILE;
RETURN HTML;
END
As you can see, I'm stuck at looping through the unknown and dynamic columns of table tmp. I read about how a cursor can be used here, but all the examples I saw make use of known columns and assign those into named variables. However, since the query itself is dynamic, I wouldn't know the names of the columns.
I'd really appreciate your time and assistance, thanks!
p.s. I've posted this as a new question because my earlier question was marked as closed as being too broad. I subsequently edited my question but it was still showing as Closed. I've therefore deleted the older question and replaced it with this one.
With a sample table as such:
CREATE TABLE tmp (ID INT, Col1 INT, Col2 INT);
The SQL you would need to generate your HTML is:
SELECT CONCAT('<table>', GROUP_CONCAT(CONCAT('<tr><td>',ID,'</td><td>',Col1,'</td><td>',Col2,'</td><tr>')), '</table>')
FROM tmp;
You can generate this using the INFORMATION_SCHEMA:
SELECT CONCAT
(
'SELECT CONCAT(''<table>'', GROUP_CONCAT(CONCAT(''<tr>'', ',
GROUP_CONCAT(CONCAT('''<td>'',', COLUMN_NAME, ',''</td>''')),
', ''</tr>'')), ''</table>'') FROM tmp'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tmp';
It is then just a case of executing this:
SET #SQL = (
SELECT CONCAT
(
'SELECT CONCAT(''<table>'', GROUP_CONCAT(CONCAT(''<tr>'', ',
GROUP_CONCAT(CONCAT('''<td>'',', COLUMN_NAME, ',''</td>''')),
', ''</tr>'')), ''</table>'') FROM tmp'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tmp'
);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Example on SQL Fiddle
ADDENDEUM
Forgot to include table headers:
SET #SQL = (
SELECT CONCAT
(
'SELECT CONCAT(''<table><tr>'',',
GROUP_CONCAT(CONCAT('''<th>'',''', COLUMN_NAME, ''',''</th>''')),
', ''</tr>'', GROUP_CONCAT(CONCAT(''<tr>'', ',
GROUP_CONCAT(CONCAT('''<td>'',', COLUMN_NAME, ',''</td>''')),
', ''</tr>'')), ''</table>'') FROM tmp'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tmp'
);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Example on SQL Fiddle
With phpMyAdmin, I can use the following SQL to change all values in the table.field mytable.Site to lower case...
UPDATE my_table SET Site=LOWER(Site)
I have a zillion tables that have this same field, and I'd like to change all of them to lower case. Is there a SQL command that will do that - change EVERY field named Site in every table to lower case (preferably without having to list every table that has that field)?
Not EXACTLY what you want,but pretty close.Tested on my machine.
First create a procedure
delimiter //
CREATE PROCEDURE test(IN tbl CHAR(64))
BEGIN
SET #s = CONCAT('UPDATE ',tbl,' SET Site=LOWER(Site)' );
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
//
delimiter ;
And for finding tables with a certain column name:
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME IN ('Site')
AND TABLE_SCHEMA='YourDB';
For calling the procedure
CALL test('tableName')
I am creating temporary tables in stored procedures. Wanted to know what commands to include in procedure to avoid conflicts?
i usually use below syntax
CREATE TEMPORARY TABLE IF NOT EXISTS temp_shipmentcount
and use
drop command at end.
should i add drop command at beginning of procedure also?
Temporary tables are connection scoped. They only exist until the connection is closed.
As per documentation on Temporary tables
You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only to the current connection, and is dropped automatically when the connection is closed. This means that two different connections can use the same temporary table name without conflicting with each other or with an existing non-TEMPORARY table of the same name...
If a connection is not closed but shared among users, then you have to drop it and re-create. But dropping a database object using a shared connection will result issues.
It would be a better option to use temporary tables with runtime generated names within a stored procedure. This is safe on using shared connection objects too.
Exampe:
set #temp_table_name := concat( 'temp_table_', ( CURRENT_TIMESTAMP + 0 ) );
set #sql := concat( 'create temporary table ', #temp_table_name );
set #select_stmt := concat( 'select this', blah, blah );
set #sql := concat( #sql, ' as ' , #select_stmt );
prepare stmt from #sql;
execute stmt;
drop prepare stmt;
-- perform opearations on temp table
--
-- in between here
--
-- and then drop it before leaving
set #drop_temp := concat( 'drop temporary table ', #temp_table_name );
prepare stmt from #drop_temp;
execute stmt;
drop prepare stmt;