MySQL - Massive structural changes - mysql

I'm working with a database that has references in nearly every table to the "user" table to track things like who last created or updated a record. Unfortunately, the user table's primary key is "username", rather than an auto incremented id. We have frequent situations where a username needs to change because of typos or changes in the user profile, and this is really time-consuming under the current design.
I want to change the structure to use an auto-incremented id, but am not finding an easy way to do it. In SqlServer, I could use a combination of introspection on references, cursors, and structural changes to do this without much effort. But from what I've read about MySQL, I (1) can only use loops from WITHIN a stored procedure and (2) can only change structure from OUTSIDE a stored procedure.
The only option I've found is the pretty tedious task of
(1) Creating a temporary table to find references to username:
CREATE TEMPORARY TABLE IF NOT EXISTS username_refs as (select table_name, column_name, constraint_name, referenced_table_name, referenced_column_name from information_schema.key_column_usage where REFERENCED_TABLE_NAME = 'user' and referenced_column_name = 'username');
(2) Building up the set of SQL statements to accomplish each task. For example, this creates a "shadow" column on each table that references username:
select CONCAT('ALTER TABLE `', table_name, '` ADD COLUMN `', column_name,'_2` bigint(20) ;') from username_refs;
This ends up being hundreds of lines of sql. Is there an easier way to accomplish this that I'm just missing?

Some people prefer to write a script in an external language to loop over the tables and format the desired ALTER TABLE statements. For example, whatever you preference is of Perl, Ruby, PHP, Python, etc. Every scripting language supports an API to access MySQL.
What you're doing is fine too. You can use SQL to generate the list of ALTER statements, save the output of that to a file, and then run the file as an SQL script.
By the way, you don't necessarily need a separate auto-increment key. You define your foreign keys to username so as to ON UPDATE CASCADE. See "Referential Actions" in https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html

Related

Run an ALTER TABLE across all like tables (containing the same schema) in MySQL database

I have a database that contains a table per client, each table has the same columns in them. We're talking a few thousand client tables.
I need to add new columns to each of these tables for new development but cannot find a way to recurse all the tables in the database to add the columns. I know MS SQL has something sp_MSforeachtable which does maybe what I'm asking but I don't know if MySQL has anything similar?
As per this previous answer in SO you could do something like this :
select concat('ALTER TABLE `',table_name,'` ADD `test` INT NOT NULL AFTER `column_x`;')
from information_schema.tables
where table_schema = 'your_db_name'
Then remove the few tables not about client (here's hoping client is the only entity to have "private table") or if possible add a condition on the table_name (like AND table_name LIKE "client_%"), and execute the whole batch.
The 2nd solution, to use procedure, is too complex (for me) for this use case, but maybe someone more skilled than me in PLSQL won't agree.

Rename all FKs and IDXs names

I am working on MySql Workbench and everytime I rename a table/column, the existing FKs and IDXs names don't change. I ended up with a model with all the FK/IDX names messed up. Is there any way to regenerate all names according to the new tables and columns names or do I have to change them one by one?
Straight on the model i haven't found any regeneration of FKs etc. A workaround is the following, but you have to forward engineer your model first in order to have a schema:
Use and customize the following statement:
SELECT TABLE_NAME, INDEX_NAME, COLUMN_NAME,
CONCAT('ALTER TABLE `your_schema`.`',TABLE_NAME,'` DROP INDEX `',INDEX_NAME,'`, ADD INDEX `fk_',TABLE_NAME,'_',COLUMN_NAME,'_idx` (`',COLUMN_NAME,'` ASC);') as statement
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'your_schema';
Customize the WHERE above in order to exclude e.g. PRIMARY indexes or anything else.
You can also set the prefix and suffix of index names that is appropriate for you in the CONCAT expression.
The first 3 columns in the above SELECT will be used in order to create the fourth expression. You can use the result of the fourth expression to batch-create the needed statements.
It may not seems the fastest solution but, once you add your final statement to your snippets, the next time will be quick and easy to regenerate your schema indexes.

MySql Finding a tree structure using Reference Keys

We have a parent table which stores the user details. Since now we were doing soft delete. However due to some legal commitments, we are forced to do a hard delete for the user details.
So the problem is the main table is referenced many places.
We could able to find all the referenced tables with the following query in MySQL
USE information_schema;
SELECT TABLE_NAME, Column_Name,Constraint_Name
FROM
KEY_COLUMN_USAGE
WHERE
REFERENCED_TABLE_NAME = 'ProjectUser'
AND REFERENCED_COLUMN_NAME = 'userid'
AND TABLE_SCHEMA = 'testproduct';
It was a success as we got all tables around 45. However the real problem is, it is possible that the child table of "ProjectUser" also may referenced somewhere else.
For example,
one of the child table UserAddress is used as foriegn Key for some other table. How can I query to bring all the tables, which reference ProjectUser, and their child tables and grand child tables?
There is no query that's going to get you out of this mess. You can write a program to successively run queries to build this structure, but you will not be able to do it all in one query.
1) Use mysqldump, write something to parse the dump and build the tree
2) Use a tool to visualize the schema such as (schemaspy)[http://schemaspy.sourceforge.net/] or (mysql workbench)[http://www.mysql.com/products/workbench/]
3) Take #AlmaDo's suggestion seriously and add ON DELETE CASCADE. You can drop an existing foreign key and readd it using the later table function. If you have problems re adding the foreign key due to constraint violation, disable keys while you re add the foreign key.

MySQL: How to find where a specific primary key is used as a foreign key in other tables?

I'm working on implementing a function to prevent removal of certain elements in a database (through the front end) if they have other items associated with them in other tables. Otherwise those other tables are looking for keys that aren't there.
If you understood that my hat is off to you.
I have many sets of tables to look through and need either a SQL query or a MySQL Workbench feature that can tell me, on entry of the primary key (column name, not actual value), if that key is used as a foreign key somewhere else.
Otherwise if anyone knows an offhand workaround, that would be great too!
SELECT
table_name, column_name
FROM
information_schema.key_column_usage
WHERE
referenced_table_name = '<table>'
and referenced_column_name = '<primary key column>'
A solution is described in this post to retrieve this information from information_Schema table.
1) If you want to work on these tables from your code, then fetch them as a container, for example ArrayList in your code and perform your logic.
2) If you want to work on these tables from your Stored Procedure, then use temporary tables to achive the same work you'd do in your java code through containers.

search simple way to alter multi tables in one time in mysql

i have a lot of tables that start with some prefix ,
and i want to alter this tables
what is the simple way to do this (instead run over all tables)
i mean something like :
ALTER TABLE LIKE tablenameprefix% ADD INDEX `NewIndex1` (`field`);
how can i do this ?
thanks
EDIT :
can i do a kind of loop not in stored procedure ?
by select the names of tables from
SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME LIKE 'tableprefix%'
You can't. What you could do though is write a stored procedure that enumerates all tables looking for your prefix and performs the necessary changes.
Given that ALTER TABLE syntax doesn't allow multiple table names, you cannot do this. You need to go through all tables in turn:
ALTER [IGNORE] TABLE tbl_name
alter_specification [, alter_specification]
Link: http://dev.mysql.com/doc/refman/5.0/en/alter-table.html
When I wanted to change multiple table's engine from MyISAM to InnoDB, instead of writing a loop I just made a full DB dump and opened it in a text editor. In the text editor I just simply changed all MyISAM words to InnoDB.
I know that this ain't proper solution but for me it was easier then writing a routine for this.
You would have to write a loop, according to the documentation you just specify the table name.
I made a stupid mistake of putting all Wordpress tables with my product tables, fortunately all Wordpress tables start with a wp_ prefix and all my other product tables have no this wp_ prefix.
I created another database named wordpress, now I want to move all tables start with wp_ to that database.
Here is what I did:
SELECT CONCAT('ALTER TABLE olddb.', table_name, ' RENAME wordpress.', table_name, ';')
FROM information_schema.tables
WHERE table_schema='olddb' AND table_name LIKE 'wp%'
INTO OUTFILE '/tmp/move_to_wordpress';
SOURCE /tmp/move_to_wordpress;
That's it.