I have a mysql database with about 8 tables that all begin with a capital letter. Any quick way to lowercase them all? Or even one by one... if i try this, RENAME TABLE Contacts TO contacts it says ERROR 1050 (42S01): Table 'contacts' already exists
Use two renames - first to a temp name and then to the lowercased:
RENAME TABLE Contacts TO contacts_
and then
RENAME TABLE contacts_ TO contacts
Of course, you should be careful not to try using an already existing table name, but if you initially had tables 'Contacts' and 'contacts_' I'd say you have way more serious problems than the case.
By checking this link, you have to:
RENAME TABLE tbl_name TO new_tbl_name
BUT : The new_tbl_name must NOT be used by another table as the name must be unique
I'm sorry for bringing back an old post. But I had problems with this aswell.
I made this function to automate the above. I didn't help in my case, but might help other people. That's why I'm posting it here.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `lowercasetables`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE tempname varchar(255);
DECLARE backupname varchar(255);
DECLARE sqlst varchar(5000);
DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.TABLES where table_schema = schema();
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO tempname;
SET backupname = concat(tempname,'_BACKUP');
SET #sqlst = CONCAT(CONCAT('RENAME TABLE ', tempname), CONCAT(' TO ', backupname));
PREPARE stmt1 FROM #sqlst;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
SET #sqlst = CONCAT(CONCAT('RENAME TABLE ', backupname), CONCAT(' TO ', LOWER(tempname)));
PREPARE stmt2 FROM #sqlst;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
UNTIL done END REPEAT;
CLOSE cur1;
END
Related
I wanted to use table names and run a statement with the table name as variable. I used cursor/fetch but when I run a statement with the variable it is not using the value of the variable but just seems to use the variable_name itself. I have seen example with concat where another variable was defined but what if I just wanted to reference the table name in a COMMAND?
DELIMITER $$
DROP PROCEDURE IF EXISTS test $$
CREATE PROCEDURE test()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE v_table_name TEXT;
DECLARE cur1 CURSOR FOR
SELECT TABLE_NAME FROM information_schema.tables where table_schema = 'rt';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done= TRUE;
OPEN cur1;
myloop: loop
FETCH cur1 INTO v_table_name;
IF done THEN
LEAVE myloop;
END IF;
COMMAND table v_table_name;
END loop;
close cur1;
END $$
If by COMMAND you mean you want to use the value of a variable as an identifier in another SQL statement... you may be able to make use of a prepared statement (in the context of a MySQL stored program).
Reference: https://dev.mysql.com/doc/refman/5.6/en/sql-syntax-prepared-statements.html
As a trivial example of what that might look like:
SET #sql = CONCAT('select * from `',v_table_name,'` limit 1');
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
SET #sql = NULL;
Note that this approach is not safe from SQL Injection vulnerabilities.
If that's not what you are looking for, I'm at a loss. I don't understand what you are referring to as a COMMAND.
We are cleaning our MySQL database and finding many rows with empty string (as value) in ENUM columns. MySQL has the nasty habit of ignoring errors like that, you know.
So, since we have hundreds of tables, I was wondering if there is a way to find which tables have this problem. Solutions involving queries, procedures or phpMyAdmin commands are welcome.
Thanks in advance!
P.S. My first question here! Yay!
So, following the suggestions in the comments, I made a procedure that prints the table name, the column name and the number of rows with empty strings instead of a ENUM value.
It works in mysql terminal app, but not in phpMyAdmin.
USE __DATABASE_NAME_HERE__;
DELIMITER //
DROP PROCEDURE IF EXISTS hunt //
CREATE PROCEDURE hunt()
BEGIN
DECLARE done INT DEFAULT false;
DECLARE current_table_name VARCHAR(255);
DECLARE current_column_name VARCHAR(255);
DECLARE my_cursor CURSOR FOR
SELECT table_name, column_name
FROM information_schema.columns
WHERE information_schema.columns.table_schema = "__DATABASE_NAME_HERE__" AND information_schema.columns.column_type LIKE "%ENUM%";
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN my_cursor;
my_loop: LOOP
FETCH my_cursor INTO current_table_name, current_column_name;
IF done THEN
LEAVE my_loop;
END IF;
SET #sql = CONCAT(
' SELECT COUNT(*) as column_count, "', current_table_name, '" AS table_name, "', current_column_name, '" AS column_name',
' FROM ', current_table_name,
' WHERE `', current_column_name , '` = ""',
' HAVING column_count > 0'
);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END LOOP;
CLOSE my_cursor;
END //
DELIMITER ;
CALL hunt();
I'm performing some database clean up and have noticed that there are a lot of columns that have both empty strings and NULL values in various columns.
Is it possible to write an SQL statement to update the empty strings to NULL for each column of each table in my database, except for the ones that do not allow NULL's?
I've looked at the information_schema.COLUMNS table and think that this might be the place to start.
It's not possible to do this with one simple SQL statement.
But you can do it using one statement for each column.
UPDATE TABLE SET COLUMN = NULL
WHERE LENGTH(COLUMN) = 0
or, if you want to null out the items that also have whitespace:
UPDATE TABLE SET COLUMN = NULL
WHERE LENGTH(TRIM(COLUMN)) = 0
I don't think it's possible within MySQL but certainly with a script language of your choice.
Start by getting all tables SHOW TABLES
Then for each table get the different columns and find out witch ones allow null, either with DESC TABLE, SHOW CREATE TABLE or SELECT * FROM information_schema.COLUMNS, take the one you rather parse
Then for each column that allows null run a normal update that changes "" to null.
Prepare to spend some time waiting :)
I figured out how to do this using a stored procedure. I'd definitely look at using a scripting language next time.
DROP PROCEDURE IF EXISTS settonull;
DELIMITER //
CREATE PROCEDURE settonull()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE _tablename VARCHAR(255);
DECLARE _columnname VARCHAR(255);
DECLARE cur1 CURSOR FOR SELECT
CONCAT(TABLE_SCHEMA, '.', TABLE_NAME) AS table_name,
COLUMN_NAME AS column_name
FROM information_schema.COLUMNS
WHERE IS_NULLABLE = 'YES'
AND TABLE_SCHEMA IN ('table1', 'table2', 'table3');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO _tablename, _columnname;
IF done THEN
LEAVE read_loop;
END IF;
SET #s = CONCAT('UPDATE ', _tablename, ' SET ', _columnname, ' = NULL WHERE LENGTH(TRIM(', _columnname, ')) = 0' );
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur1;
END//
DELIMITER ;
CALL settonull();
I'm working on an old database already in use for years and really crappy designed.
There is a table, "Articles", which contains a "code" column that will be our PK.
And many tables like "idXXXXX" where XXXXX is a "code" value with exactly the same structure.
I looked at the application using this database and saw that relations between tables is made there.
I'm not affraid of redesign the database access in the application, but I don't want to lose years of entries in the database.
I want to create a "campain" table which will have an "id" PK and a "id_code" as FK linking "campain" to "articles"
I'm not a SQL master but I know I can get tables names with
SELECT TABLE_NAME FROM INFORMATION_SCHEMA WHERE TABLE_NAME LIKE 'id%'
But I have really no idea about how to deal with the result (which is fine).
So how can I access to every tables named "idXXX" and insert every rows in the "campain" table + set "id_code" column to "XXX"?
Here is the procedure I saved (I didn't add every fields in the INSERT line for testing purpose) :
CREATE PROCEDURE JoinAllTables()
BEGIN
DECLARE done INT default 0;
DECLARE tableName CHAR(9);
DECLARE buffStr CHAR(7);
DECLARE buffId INT default 0;
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'id%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tableName;
IF done THEN
LEAVE read_loop;
END IF;
SET buffStr = SUBSTRING(tableName, 3);
SET buffId = CAST(buffStr AS SIGNED);
set #sql = CONCAT("INSERT INTO campagnes(id, id_code) SELECT null, bufId FROM ",tableName); # Dynamically building sql statement
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur1;
END;
As u can see, I sub 'idXXXXX' to 'XXXXX' then CAST it AS INTEGER (SIGNED).
But I guess that in the "INSERT INTO" line, second tableName doesn't point to the variable. That's why I'm getting a
"#1446 - Tabble 'bddsoufflage.tablename'doesn't exist" Error :) Any idea ?
Edit: Updated answer
We can't have the tableName dynamically changed inside a prepared statement, so we must go through DynamicSQL to build the query using CONCAT, then compile the SQL with PREPARE, EXECUTE it and DEALLOCATE it.
DELIMITER //
CREATE PROCEDURE JoinAllTables()
BEGIN
DECLARE done INT default 0;
DECLARE tableName CHAR(9);
DECLARE buffStr CHAR(7);
DECLARE buffId INT default 0;
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'id%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tableName;
IF done THEN
LEAVE read_loop;
END IF;
SET buffStr = SUBSTRING(tableName, 3);
SET buffId = CAST(buffStr AS SIGNED);
set #sql = CONCAT("INSERT INTO campagnes(id, id_code) SELECT null, ", buffId, " FROM ",tableName); # Dynamically building sql statement
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur1;
END; //
See also this answer MySQL Pass table name to cursor select
Old answer
The procedure should look something like this. Thanks Mchl for providing an Insert Into query example, I simply added it to the rest of the procedure.
DELIMITER //
CREATE PROCEDURE JoinAllTables()
BEGIN
DECLARE done INT default 0;
DECLARE tableName CHAR(7); # Variable to contain table names CHAr(7) is assuming id + 5Xs as characters.
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA WHERE TABLE_NAME LIKE 'id%'; # Create a cursor to iterate over the tables
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tableName;
IF done THEN
LEAVE read_loop;
END IF;
#Your Insert statement here, using tableName as a field.
INSERT INTO campain (id, id_code, otherfields) SELECT null, tableName, otherfields FROM tableName;
END LOOP;
CLOSE cur1;
END;//
Easiest way would be to run the information_schema query you have within some script (PHP,Python,Perl - whichever suits you best) and use it's results to create queries like:
INSERT INTO
campain (id, id_code, otherfields)
SELECT
null, 'idXXXX', otherfields FROM idXXXX
I have a joomla mysql database with a table name prefix of "jos_" on all of my table names. But I would like to remove it from all of my tables. I understand how to rename each table, one at a time, but I have 600 tables. Is there an easy to run a sql query to do this.
If someone has a solution, could you please post the exact sql query I can use?
In phpmyadmin select all tables of your database.
From the dropdown 'With selected:' choose 'Replace table prefix'
Set from->to replacement.
DONE
You can generate the necessary statements with a single query:
select 'RENAME TABLE ' || table_name || ' TO ' || substr(table_name, 5) ||';'
from information_schema.tables
Save the output of that query to a file and you have all the statements you need.
Or if that returns 0s and 1s rather the statemenets, here's the version using concat instead:
select concat('RENAME TABLE ', concat(table_name, concat(' TO ', concat(substr(table_name, 5), ';'))))
from information_schema.tables;
You can create your own stored procedure to rename your tables, with that you don't need to open an external editor everything will be done on the server:
delimiter //
CREATE PROCEDURE rename_tables( IN db CHAR(255), IN srch CHAR(255), IN rplc CHAR(255) )
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE from_table CHAR(255);
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=db;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
read_loop: LOOP
IF done THEN
LEAVE read_loop;
END IF;
FETCH cur1 INTO from_table;
SET #to_table = REPLACE(from_table, srch, rplc);
IF from_table != #to_table THEN
SET #rename_query = CONCAT('RENAME TABLE ', db, '.', from_table, ' TO ', #to_table, ';');
PREPARE stmt FROM #rename_query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END LOOP;
CLOSE cur1;
END//
delimiter ;
Usage:
CALL rename_tables('test', 'jos_', '');
Update: This was my first MySQL stored procedure and I ran into the 6 years old bug #5967 which was quite annoying, your variable names must be different from the field names, because if they aren't you'll get NULL values in your variables.
So be aware of that if you decide to write a MySQL stored procedure.