Finding out which tables are different in two versions of a database - mysql

I have 2 versions of a database (say db_dev and db_beta). I've made some changes in the db_dev database - added some tables, and changed a few columns in some existing tables. I need to find out the list of table names in which changes have been made.
I can easily find out the tables I've added by running the following query on the information_schema database:
SELECT table_name
FROM tables
WHERE table_schema = 'db_dev'
AND table_name NOT IN (SELECT table_name
FROM tables
WHERE table_schema = 'db_beta');
How do I get the table_names whose column_names do not match in the two database versions?

There are many ready made tools available which can give you changed schema by comparing two databases. Here are some tools which can serve your purpose :
Red-Gate's MySQL Schema & Data Compare
Maatkit
MySQL Diff
SQL EDT
Red-Gate's MySQL Compare is best tool for this purpose. Its paid though but they provide 14 days free trial version if you want to do something temporary.

Using information_schema, here is how it works.
First, you know that the information_schema.COLUMNS table contains the columns definition. If one column has been changed, or a table does not exist, it will reflect in the information_schema.COLUMNS table.
Difficult part is that you have to compare all columns of your COLUMNS table. So, you have to select TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,ORDINAL_POSITION,COLUMN_DEFAULT, and so on (which is subject to evolution depending on your MySQL version).
The column list is the result of the following query:
SELECT GROUP_CONCAT(column_name)
FROM information_schema.COLUMNS
WHERE table_schema="information_schema"
AND table_name="COLUMNS" AND column_name!='TABLE_SCHEMA';
After that, we just have to SELECT TABLE_NAME, <column_list> and search for columns which appear once (column inexistent in other table), or where columns have two different definitions (columns altered). So we will have two different count in the resulting query to consider the two cases.
We will so use a prepared statement to retrieve the list of column we want, and grouping the result.
The resulting query does all the process for you:
SELECT CONCAT(
"SELECT DISTINCT TABLE_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA IN('db_dev', 'db_beta')
GROUP BY table_name, COLUMN_NAME
HAVING count(*)=1 OR
COUNT(DISTINCT CONCAT_WS(',', NULL, ",
GROUP_CONCAT(column_name)
,"))=2;")
FROM information_schema.COLUMNS
WHERE table_schema="information_schema"
AND table_name="COLUMNS" AND column_name!='TABLE_SCHEMA'
INTO #sql;
PREPARE stmt FROM #sql;
EXECUTE #sql;

The following solution does not use an sql query like you tried and does not give you a real list of tables, but it shows you all the changes in both databases.
You can do an sql dump of both database structures :
mysqldump -u root -p --no-data dbname > schema.sql
Then you can compare both files, e.g. using the diff linux tool.

Related

MySQL get list of tables ending with specific name and it's (table's) comment

I have multiple tables in my multiple databases.
On different servers, i use MySQL / PostgreSQL / MS SQL.
I keep short table namesbut the comments given to the tables are with full explanation.
I want query that will show me tables ending with "com" and also the comment given to each table (table's comment).
In MySQL, I know:
SELECT table_name FROM information_schema.tables where table_name like "%com"
But this shows all tables from all databases.
For MySQL, check out following:
SELECT table_name FROM information_schema.tables;
will show all table names in all databases;
SELECT table_name,table_comment FROM information_schema.tables
will show all table names + comment in all databases;
interesting thing, you can fire
SELECT * FROM information_schema.tables;
to know what all info you can get of a table.
SELECT table_name,table_comment FROM information_schema.tables
where
table_schema = 'sifr_b';
will show all table names + comment in "sifr_b" database;
SELECT table_name,table_comment FROM information_schema.tables
where
table_schema = 'sifr_b' and
table_name like "%com";
will show those table names + comment in "sifr_b" database, that have table name ending with "com";

MYSQL - copy tables with specific prefix between databases

Is there a SQL command to copy many tables with specific prefix (ie yot_) between two MYSQL databases? The DB user has access to both of the DB
There's no SQL statement of any kind that operates on tables using wildcards. You must name tables explicitly.
You can, however, generate the statements by querying the INFORMATION_SCHEMA:
SELECT CONCAT(
'RENAME TABLE my_old_schema.`', TABLE_NAME, '` '
' TO my_new_schema.`', TABLE_NAME, '`;'
) AS _stmt
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'yot\_%'
AND TABLE_SCHEMA='my_old_schema';
That's an example of generating a series of RENAME TABLE statements, which will move the tables from one schema to another. But it demonstrates the technique
You can try to make table-copy instead of move, with CREATE TABLE new_table LIKE old_table; followed by INSERT INTO new_table SELECT * FROM old_table;

Dropping all schemas with no tables

I want to drop all databases with zero tables I was able to get the databases with tables using
SELECT table_schema, count(table_name) FROM information_schema.tables group by table_schema
But how can I delete the dbs not in this list. I can't do it manually because there are more then 500 dbs there.
About to know schemas without tables, you can try this:
SELECT * FROM information_schema.schemata S
WHERE NOT EXISTS
(SELECT 'TABLE' from information_schema.tables T
WHERE T.table_schema = S.schema_name)
Because in system table SCHEMATA you'll find all schemas of your server and in table TABLES you'll find all tables in all schemas
The upper query must be input on cursor, so you must use a prepared statement to execute your cursor, because your DROP DATABASE has a variable (your schema_table) and it can be ran only with a prepared statement
Used the method posted by #dnoeth in the comments with a slightly diffrent query to get the drop commands and then with some Notepad++ magic executed them to drop all empty databases
SELECT concat('drop database ',schema_name) FROM information_schema.schemata
WHERE schema_name NOT IN
(SELECT TABLE_SCHEMA FROM information_schema.tables)

How would I delete a single column in all tables in MYSQL

I have a column 'seq' in every table of my database that I would like to delete easily.
I have to do this on occasion in MySQL and am hoping this can be automated.
There isn't a simple magical expression to just do this. You need to generate a list of SQL statements and then run them, somehow.
(Most database folks don't routinely drop columns from a database in production; it takes a lot of time during which the tables are inaccessible, and it's destructive. A fat-finger error could really mess you up.)
You might start by using the information_schema in MySQL to discover which of your tables have a seq column in them. This query will return that list of tables for the database you're currently using.
SELECT DISTINCT TABLE_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND COLUMN_NAME = 'seq'
You could then adapt that query to, for example, create a list of statements like this.
SELECT DISTINCT
CONCAT('UPDATE ',TABLE_NAME, ' SET seq = 0;') AS stmt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND COLUMN_NAME = 'seq'
This will produce a result set like this:
UPDATE table_a SET seq = 0;
UPDATE table_b SET seq = 0;
UPDATE user SET seq = 0;
Then you could run these statements one by one. These statements will zero out your seq columns.
Edit
You can also do
CONCAT('ALTER TABLE ',TABLE_NAME, ' DROP COLUMN seq;') AS stmt
to get a drop column statement for each table.
But, you might consider creating views of your tables that don't contain the seq columns, and then exporting to PostgreSQL using those views. If your tables are significant in size, this will save you a lot of time.

Select something with location unkown from all tables in database in mysql

I have a varchar with the value of say Foo somewhere in my database and I don't know where exactly.
Is it possible to create a query that will search all tables and all columns for this content? Similar to grep
There isn't an easy way to do this, but you could use the information schema to find all your varchar columns.
SELECT table_name, column_name
FROM information_schema.columns
WHERE data_type = 'varchar';
You could then write a query to produce a list of queries that you would need to run to search for your term.
SELECT CONCAT(
'select ', column_name,
' from ', table_name,
' where ', column_name, ' like \'%foo%\''
) AS stmt
FROM information_schema.columns
WHERE data_type = 'varchar';
A more advanced example might insert matches into a results table along with the table and column names.
There is a stored procedure here (http://forge.mysql.com/tools/tool.php?id=232) for MySQL which will create a table for storing output, then loop through information_schema database's COLUMNS table to obtain all database's table and column names. Next execute a count() query on database.table for each column with appropriate search string in where condition. If count() > 0, that perticular column has the search term, so it will insert that triplet (database name, table name, column name) into a table. Last Select * from table to view respective database table and column names having the search term.
I found a very very simple way of doing it.
mysqldump -u user -p mydatabase | grep foo