I have a project where I want to be able to manage several instances of the same database on several people's localhosts. I want each developer to be able to reset their DB back to the canonical origin no matter what state they get their DB into. To this end I maintain a standard database file. It holds the schema using CREATE TABLE table_name IF NOT EXISTS {
However, I want to be able to add to the starting table structures as needed as this project moves along. To do this, I would love to be able to do something like the following ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name but that does not seem to exist. I did notice a stored procedure floating around the internet that solves this, but I wanted to know if something simpler is able to achieve the goal I have in mind. Thank you for the time and help.
It won't be possible to do it with plain SQL. Stored procedure should work the best: read information_schema and check if the column is present. If not - execute the alter statement.
One option is to execute your ALTER statement without checking anything:
ALTER TABLE table_name ADD column_name VARCHAR(40);
(change VARCHAR(40) to whatever you need)
If the column didn't already exist, then the statement creates it.
If the column already existed, the statement does nothing and returns an error. Just ignore the error and continue.
Related
Is there any way to detect when an ALTER TABLE statement is executed in MySQL? For example, if the following statement were executed on some_table, is there any way to detect that the column name changed from column_name_a to column_name_b and log it in another table in the DB?
ALTER TABLE `some_table`
CHANGE COLUMN `column_name_a` `column_name_b` VARCHAR(255) NULL DEFAULT NULL;
Thanks.
To my knowledge it is unfortunately not possible to put triggers on the INFORMATION_SCHEMA tables, since they are strictly spoken views and triggers can't be made to work on views. If triggers would be possible on the INFORMATION SCHEMA, then you could have a trigger on updates of the INFORMATION_SCHEMA.COLUMNS table to identify name changes.
However, what you can do is one of the following things:
option 1) Maintain a real table with all column names. Then create a function that checks for a discrepancy between the INFORMATION_SCHEMA.COLUMNS table abd your table. If there is one, you know the name has changed. You need to copy over the new name to your column name table and do whatever else you wanted to do upon name change.
The function to check for discrepancies then must be run periodically via the mysql scheduler in order to detect name changes as quickly as possible. Note that this is not a real time solution. There will be a lag between the ÀLTER TABLE command and its detection. If this is unacceptable in your scenario you need to go with
option 2) Do not call ÀLTER TABLE directly, but wrap it in a function. Within this function you can also call other functions to achieve what you need to achieve. If may be worth while to formulate the needed steps in a higher programming language that you use to drive your application. If this is not possible, you will be limited to the possibilities that are offered in functions/procedures in the mysql environment.
Sorry to not have a simpler way of doing this for you.
I have recently installed a new computer with Percona Server 5.6 instead of MySQL 5.6, and using InnoDB/XtraDB mostly, FWIW. The database I'm working on is merely a testing ground, but I have 1 issue: after I add a column to a table (or even remove one), I usually forget to INSERT or otherwise change another table's data, which keeps track of what column names are in which table; each table has ASCII name along with a number, and this number is the only difference between table names for simplicity. So, is there a way to auto-update the "relation" table so that the column name and table's number are added or changed, instead of using a cronjob ?
Now that I think, I could DROP that table and use information_schema instead ...
EDIT 0: Don't let the above realization stop you; it's just good to know if this is possible before going for a possible other way.
Yes, relying on the 'INFORMATION_SCHEMA.COLUMNS' may be best.
Unfortunately mysql does not support DDL TRIGGER events, as this would be what you are looking for.
triggers allow you to perform many SQL and procedural operations before insertion, update or deletion of rows in a specific table. However to the best of my knowledge - and I would be stoked if I were wrong - you cant set TRIGGER events on DDL statements like ALTER and DROP TABLE...
However still take the time to learn about triggers - they save a lot of time by eliminating the need for cronjobs and external updates for things like aggregate values.
https://dev.mysql.com/doc/refman/5.6/en/trigger-syntax.html
I have a table with 120 columns. I need to set up audit trail which would log any column if it was changed. As it is now, I guess I have to set up a trigger with condition something like this for every column:
IF(NEW.columnName != OLD.columnName)
THEN //log the old value
This would need to be done 120 times... While I would have accepted this approach 20 years ago, today I refuse to believe it's impossible to automate such a simple procedure finding changed columns automatically.
This is what I discovered so far:
Neither NEW nor OLD is a table, it's a sort of a language construct, therefor you can't do "SELECT NOW.*" or something similar.
Dynamic SQL is not allowed in triggers (this could have solved the problem).
Procedures using dynamic SQL are not allowed in triggers (seriously, Oracle, it looks like you have worked really hard to disable this feature no matter what).
I was thinking to use BEFORE and AFTER triggers in conjunction with temporary tables and variables which would have possibly solved the problem, however yet again dynamic SQL would be required. I feel like I hit a dead end.
Is there a solution to this at all?
A side question: would this be possible in PostgreSQL?
UPDATE: I found 2 potential solutions however neither of them look clear enough to me:
using EVENTS as a workaround to use triggers in conjunction with dynamic SQL workaround. I have to admit, I don't quite get this, does this mean that EVENT fires every second no matter what?
This article says that it is possible to use dynamic SQL inside trigger as long as temporary table is used with it. That is still using dynamic SQL, so I don't quite understand.
interesting, I was facing the same problem couple of years ago with implementing dynamic trigger-based audit log. The solution I came up with was to simply generate the SQL trigger code which then can be (automatically) applied to replace old trigger definitions. If memory serves, I created few SQL templates which were processed by a PHP script which in turn was outputting complete trigger definitions based on "SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE ..." Yes, the trigger code was huge, but it worked! Hope that helps a little =)
i did this for one of the projects by creating a shadow table. if you are not dealing with millions of updates, this might work
when the user logs in, SET #user_id = { logged in user id }
create a trigger on the table before update to copy the row to be modified to a shadow table with the same structure ( note that you cannot have a primary key in the shadow table nor unique keys )
add additional columns to the shadow table ( modified_by, modified_on )
create a small php script to show the diff between columns - this way you dont touvh the existing php code base
if you are dealing with lots of updates and want to keep the shadow table small, a cron can be written to parse the shadow table and identify which column changed and only store this info to another table
Is there a way to do this?
In case the DBMS command history got cleaned or, in my case, when many ALTER TABLE were used in the course of time.
I'm using MySQL.
Yes, it is as simple as
SHOW CREATE TABLE yourtable;
This will include all the subsequent ALTER TABLE statements. You cannot retrieve the table's original state.
Here is the relevant documentation
I want to run this on my table:
ALTER TABLE table_name MODIFY col_name VARCHAR(255)
But my table is huge, it has more than 65M (65 million) rows. Now when I execute, it takes nearly 50mins to execute this command. Any better way to alter table?
Well, you need
ALTER TABLE table_name CHANGE col_name new_name VARCHAR(255)
But, you are right, it takes a while to make the change. There really isn't any faster way to change the table in MySQL.
Is your concern downtime during the change? If so, here's a possible approach: Copy the table to a new one, then change the column name on the copy, then rename the copy.
You probably have figured out that routinely changing column names in tables in a production system is not a good idea.
another variant to use percona toolkit
https://www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html
You can deal with schema change without downtime using Oak.
oak-online-alter-table copies schema of original table, applies your changes and then copies the data. The CRUD operations can still be invoked as oak puts some triggers on original table so no data is going to be lost during the operation.
Please refer to other question where author of oak gives detailed explanation about this mechanism and also suggests other tools.