Postgresql: how to change the table definition - mysql

The problem: I'm searching for an alternative solution to change column definition in postgresql.
I would like to do something that is similar to the mysql solution:
ALTER TABLE table_name
CHANGE [COLUMN] old_col_name new_col_name column_definition
Is there a way to use CHANGE COLUMN similar to what I've described previously? Is there any way to easily change the column definition in postgres?
I'd like to use a similar method to my example because I'm building the alter query from code.

There is no direct equivalent to MySQL's CHANGE COLUMN clause in PostgreSQL. You'll need to specify the column definitions parts one by one. See documentation for ALTER TABLE. Fortunately you don't need to detect differences between old definition and new in typical cases, if the change is redundant PostgreSQL will just ignore it. e.g ALTER COLUMN x DROP NOT NULL will still work when the column is already nullable.

Related

Table traversing with multiple operations in ALTER TABLE

Some databases, like MySQL [1] and PostgreSQL [2], support bundling of certain compatible ALTER TABLE statements (as non-standard SQL).
For example we can have:
ALTER TABLE `my_table`
DROP COLUMN `column_1`,
DROP COLUMN `column_2`,
...
or
ALTER TABLE
MODIFY `column_1` ... ,
MODIFY `column_2` ... ,
instead of having individual statements:
ALTER TABLE `my_table` DROP COLUMN `column_1`;
ALTER TABLE `my_table` DROP COLUMN `column_2`;
or
ALTER TABLE `my_table` MODIFY `column_1` ... ;
ALTER TABLE `my_table` MODIFY `column_2` ... ;
etc
For comparison of the same feature, PostgreSQL [2], which also implements this, will perform all operations in a single scan:
The main reason for providing the option to specify multiple changes in a single ALTER TABLE is that multiple table scans or rewrites can thereby be combined into a single pass over the table.
Although for DROP COLUMN specifically it will often not even need do that:
The DROP COLUMN form does not physically remove the column, but simply makes it invisible to SQL operations...
Questions:
Would the multi-column statement result in traversing all the rows just once and performing all changes needed?
How does MySQL actually perform DROP COLUMN? Does it also "hide" the columns first, or does it delete the data straight away?
Assumptions:
Using InnoDB
No indexes/complex defaults are involved in any of the columns we want to change/drop (so basically changes that would not require a temporary table when run as individual alter statements)
References:
[1] MySQL ALTER TABLE docs
[2] PostgreSQL ALTER TABLE docs
MySQL's InnoDB:
(This does not really answer the Questions, but provides a little more insight in the the bigger question of ALTER.)
If any of the alters needs to copy the table over, you are probably better off putting all alters into the same statement. Changing the PRIMARY KEY, for example, requires rebuilding the data that is clustered with the PK.
Some alters can be achieved by simply altering the schema; these are virtually instantaneous, and could be done via separate alter statements. Adding an option to ENUM was implemented long ago.
Some alters need some form of scan, but can do it "in the background". DROP INDEX can be done by quickly "hiding" it, then freeing up the BTree in the background.
I have left out a grey area in which you batch 'simple' alters. One would hope that ALTER is smart enough to simply go through them quickly, rather than deciding to copy the table over.
I got some useful feedback but decided to respond to my own question to provide a more concrete set of answers.
Would the multi-column statement result in traversing all the rows just once and performing all changes needed?
Yes, if the alter statement results in rebuilding the table then it only needs to do it once.*
* This answer comes from my own testing and other mostly anecdotal evidence (including #Uueerdo 's in this post). It would be useful to have some official docs for this...
How does MySQL actually perform DROP COLUMN? Does it also "hide" the columns first, or does it delete the data straight away?
MySQL will rebuild the table in place (rather than create a copy or just change metadata) for most column operations. Each specific case can be found in the Online DDL docs for InnoDB.
A few operations like renaming a column or setting a default value will just alter metadata, so they don't require a table rebuild.
However, dropping a column DOES require a full table rebuild.

Retrieve CREATE TABLE code of an already existing 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

How do you change an autoincremented columns starting value through liquibase?

I am using MySql for my database. I have found how to set a column's starting autoincrement value when creating a table, but I need to know how to set a new starting value for an existing column. What does the liquibase script look like to do that?
The MySQL syntax is pretty straightforward:
ALTER TABLE mytable AUTO_INCREMENT = val ;
(Note that this is really a table attribute, not a column attribute. There can be only one column in a table declared to be AUTO_INCREMENT.)
This syntax isn't supported in SQL Server or Oracle; Oracle doesn't even have a concept of an "auto_increment" column, apart from a SEQUENCE object and a TRIGGER. SQL Server calls it an IDENTITY property. So I don't know how this statement would be represented in "liquibase" syntax, other than specifying that this statement is native MySQL syntax.
You can use addAutoIncrement (http://www.liquibase.org/documentation/changes/add_auto_increment.html) to change your existing AUTO_INCREMENT column.
Don't forget to specify columnDataType in the addAutoIncrement.
I used this yesterday for our project and it worked (for MySQL).

Change column name without recreating the MySQL table

Is there a way to rename a column on an InnoDB table without a major alter?
The table is pretty big and I want to avoid major downtime.
Renaming a column (with ALTER TABLE ... CHANGE COLUMN) unfortunately requires MySQL to run a full table copy.
Check out pt-online-schema-change. This helps you to make many types of ALTER changes to a table without locking the whole table for the duration of the ALTER. You can continue to read and write the original table while it's copying the data into the new table. Changes are captured and applied to the new table through triggers.
Example:
pt-online-schema-change h=localhost,D=databasename,t=tablename \
--alter 'CHANGE COLUMN oldname newname NUMERIC(9,2) NOT NULL'
Update: MySQL 5.6 can do some types of ALTER operations without rebuilding the table, and changing the name of a column is one of those supported as an online change. See http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html for an overview of which types of alterations do or don't support this.
If there aren't any constraints on it, you can alter it without a hassle as far as I know. If there are you'll have to remove the constraints first, alter and add the constraints back.
Altering a table with many rows can take a long time (though if the columns involved are not indexed, it may be trivial).
If you specifically want to avoid using the ALTER TABLE syntax created specifically for that purpose, you can always create a table with almost the exact same structure (but different name) and copy all the data into it, like so:
CREATE TABLE `your_table2` ...;
-- (using the query from SHOW CREATE TABLE `your_table`,
-- but modified with your new column changes)
LOCK TABLES `your_table` WRITE;
INSERT INTO `your_table2` SELECT * FROM `your_table`;
RENAME TABLE `your_table` TO `your_table_old`, `your_table2` TO `your_table`;
For some ALTER TABLE queries, the above can be quite a bit faster. However, for a simple column name change, it could be trivial. I might try creating an identical table and performing the change on it in order to see how much time you're actually looking at.

Must I include all column attributes in an SQL statement when I want to alter only one?

I have a MySQL database that, I would like to annotate by adding comments to all of the columns,
From what I read on the MySQL documentation, it is necessary to include the data type and all attributes when changing any single one of these.
For example, I must type
ALTER TABLE `dbname`.`tablename`
CHANGE COLUMN `columnname` `columnname`
INT(11) NULL DEFAULT NULL COMMENT 'this is my comment`;
It would be much faster for me to avoid having to restate the column info for each change, for example, by only having to submit a command such as:
ALTER TABLE `dbname`.`tablename`
CHANGE COLUMN `columnname`
COMMENT 'this is my comment`;
Are there any options for adding comments that do not require me to restate the table structure?
The documentation is pretty clear that CHANGE COLUMN requires the full column definition:
CHANGE [COLUMN] old_col_name new_col_name column_definition
Anything optional would be in brackets.
Your best bet is probably to write a little one-off script to produce your ALTER TABLE commands based on the table's current schema. You should be able to extract the column definitions from whatever data access layer you're using.