How to alter MySQL table without losing data? - mysql

In my application, I make some changes and upload them to a testing server. Because I have no access to the server database I run ALTER commands to make changes on it.
Using a method I ran the following command on server:
ALTER TABLE `blahblahtable` ADD COLUMN `newcolumn` INT(12) NOT NULL
After that, I found that the all the data of the table has been removed. Now the table is blank.
So I need to alter the table without removing his data. Is there any way to do that?

Your question is quite obvious. You're adding a new column to the table, and setting it to NOT NULL.
To make things clearer, I will explain the reaction of the server when you run the command:
You add a new column, so every row of the table has to set a value for that column.
As you don't declare any default value, all the rows set null for this new column.
The server notices that the rows of the table have a null value on a column that doesn't allow nulls. This is illegal.
To solve the conflict, the invalid rows are deleted.
There are some good fixes for this issue:
Set a default value (recommended) for the column you're creating.
Create the column without the NOT NULL, set the appropiate values, and then make the column NOT NULL.

You can create a temp table, pass all the information from the table you want to alter, and then return the info to the altered table.

Related

MySQL Add Column with Online DDL

I'm currently trying to add a column to a table of ~25m rows. I need to have near-0 down time, so was hoping to use online DDL. It runs for a while, but eventually runs into the issue:
"Duplicate entry '1234' for key 'PRIMARY'"
[SQL: u'ALTER TABLE my_table ADD COLUMN my_coumn BOOL NOT NULL DEFAULT false']
I think this is happening because I'm running INSERT ... ON DUPLICATE KEY UPDATE ... operations against the table while running the operation. This seems to be a known limitation.
After this didn't work, I tried using the Percona pt-online-schema-change tool, but unfortunately, because my table has generated columns, that didn't work either with error:
The value specified for generated column 'my_generated_column' in table '_my_table_new' is not allowed.
So, I'm now at a loss. What are my other options for adding a column without blocking DML operations?
Your Alter statement is creating a non nullable column with a default of false. I'd suspect this to place an exclusive lock on your table, attempt to create the column, then setting it to False across each row.
If you don't have any available downtime, I'd suggest you
Add the column as nullable and with no default
ALTER TABLE my_table ADD COLUMN my_coumn BOOL NULL;
Update the values for existing rows to false
update my_table set my_coumn=false;
Alter the table a second time to be not nullable and with a default.
ALTER TABLE my_table modify my_coumn BOOL NOT NULL DEFAULT false;
Alternatively you could use something like Percona which manages schema changes using triggers and is meant to offer the ability to update schemas without locking the table.
Either option I'd suggest you test in your development environment with some process writing to the table to simulate user activity.

mysql alter column allow null takes forever

I have a large table with a column that has currently NOT NULL
I now tried to alter the table to allow nulls for this column. However, the query never finishes. Is this to be expected or is there a better way to do this?
That happens and I think the best approach is to create a new table schema and load the old table into that new table.

Insert into table with auto-increment field

I have two tables called HRData and HRDataHistory. HRDataHistory has the same structure as HRData except the first column is an autoincrement field and the last column is a DateTime field.
HRData has a trigger:
CREATE TRIGGER [HR].[HRData_History]
ON [HR].[HRData]
AFTER INSERT, UPDATE
AS
INSERT INTO HR.HRDataHistory
SELECT *, GETDATE()
FROM inserted
;
GO
This is working on an existing development machine. I am trying to mirror this relationship on my local sql server instance so that I can test some changes. Using SSMS I used 'Script Table as Create To...' and created the structure of each table and index on my local sql server instance. However when I do this for the trigger I get the following error:
An explicit value for the identity column in table 'HR.HRDataHistory' can only be specified when a column list is used and IDENTITY_INSERT is ON.
I know the preferred method would be to specify the columns, but I want to mirror production which does not currently do that and further I want to understand why it is working in production but not on my test database.
You're getting this error because you're trying to insert data into an IDENTITY column, which auto-populates itself whenever you insert another row in that table.
Off the top of my head, you can do something like below (although I believe there are more elegant solutions and I do not guarantee that this is a safe solution, nor have I tried something like this and I recommend testing on a TEST database before trying in production/LIVE):
add another column to HRDataHistory table which does not have identity set on it (because you cannot remove identity form a colum once set), but must have the same datatype as the current ID (IDENTITY) column
use a UPDATE query to move all of your ID's from your IDENTITY column to your new column:
UPDATE HRDataHistory
SET new_column = ID
Drop the IDENTITY column (but this might have grave implications if you have any FK set on it and possibly other objects that use it):
ALTER TABLE HRDataHistory
DROP COLUMN ID
Rename the "new_column" to the name of your previous IDENTITY column:
EXEC sp_RENAME 'HRDataHistory.new_column' , 'ID', 'COLUMN'
At this point I believe you can use your trigger to "copy" the newly inserted data from the HRData table into the HRDataHistory, since the column names should match and there is no more conflict due to IDENTITY.
Again, this might (not guaranteed) work so I recommend you first check on a TEST environment.

Will MySQL ALTER TABLE reformat field data?

I need to alter a table to change the Type of a column. If the current column Type is DECIMAL(8,2) and I alter that column to be DOUBLE, will the already-existing data in the column also be changed to reflect the column's new Type?
It should. However, always be safe when altering existing tables.
My preferred way of doing this type of operation is:
make a backup
create a new column
update all rows moving the old data over to new column
inspect the new column for anything wrong and fix if necessary
delete the old column

MySQL: making a column unique?

I have a table that is in production. I realize that some of the columns should be unique. Is it safe to go into phpMyAdmin and change those columns to make it unique?
ALTER TABLE `foo` ADD UNIQUE ( `bar` )
Follow the below steps to apply unique column value from phpmyadmin panel:
Go to the table structure. Click on the unique keyword as like below -
Click on the ok from confirmation box -
Unique value constraint for column will apply.
Or you can run mysql query:
ALTER TABLE user ADD UNIQUE(email);
You do not have duplicates -> will apply the key without issues
You do have duplicates -> will give an error message, nothing happened to your data
All is unique, except several rows with NULL in them, unique constraint is still applied, as NULL is not checked when checking for unique values (you can have the entire table have a NULL value in a unique field without any error message).
One more thing, if you have a prod DB, you must also have a dev DB which you can test on without fear, right?
If there are already some duplicate values in those columns, then this will generate an error. If there aren't any duplicate values in those columns, then you will be fine.
It will only be a problem if the pre-existing values on the table are not unique, otherwise I don't think there will be any problem.
I had this problem and my values were not unique. I also couldn't find an easy way to edit this problem in PHPMyAdmin. Here's how I solved it:
I clicked into the table I needed to update
I exported the table, changing it to be a CSV export and then edited
it manually to update the non-unique values.
Making sure I was still in the table I had exported (because I
wanted to keep the headers intact), I imported my newly saved CSV
Hope that saves someone some time in the future.