"Alter Column" differences between MySQL and PostgreSQL
SQL is a standard that would make our lives easier if it was implemented consistently across major database back-ends. Beyond simple queries it is rarely the case, and one example is table alteration. Today I was writing an abstraction over JDBC that will be used behind Datazenit Schema Builder, and I got reminded about those differences once again.
Postgres has a nice syntax to modify columns in a table. For example you can change each attribute separately.
ALTER TABLE "my_table" ALTER COLUMN "foo" TYPE varchar(10);
MySQL is a bit more clumsy than Postgres and allows changing a column as only a whole. It means you must specify each attribute if you don’t want to lose existing column settings.
ALTER TABLE `my_table` MODIFY COLUMN `foo` VARCHAR(10)
CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
As you can see this introduces a lot of unnecessary paramaters to the query. You must also know all the attributes beforehand. Another thing you may have noticed is the difference between identifier quote symbols, but that’s a topic for another time.
How to get all settings for a column if MySQL requires them? There are several options, but an convenient way is a SHOW FULL COLUMNS
query.
SHOW FULL COLUMNS FROM `my_table` WHERE Field = "foo";
The output will be similar to the table shown below except with even more info.
Field | Type | Collation | Null | Default |
---|---|---|---|---|
foo | varchar(10) | utf8 | YES | NULL |
You can use this data to build the definition of column on the server side. For those that prefer a one-liner, StackOverflows provides a solution. It is a single MySQL query that returns the final column definition. Below is a little bit modified version that uses CONCAT_WS instead of CONCAT with manual spaces and includes all column parameters.
SELECT
CONCAT_WS(
' ',
COLUMN_NAME,
'NEW_TYPE',
IF(IS_NULLABLE = 'NO', 'NOT NULL', '')
IF(COLUMN_DEFAULT IS NOT NULL, CONCAT('DEFAULT ', QUOTE(c.COLUMN_DEFAULT)), ''), ,
EXTRA,
IF(COLUMN_COMMENT IS NOT NULL, CONCAT('COMMENT ', QUOTE(c.COLUMN_COMMENT)), '')
) AS s
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_SCHEMA = 'test'
AND TABLE_NAME = 'my_table'
AND COLUMN_NAME = 'foo'
Examine and test before using any of this. I will stick to manipulating the data from server side, because my Schema Builder must be able to change all parameters not just the type, and writing a large query for each parameter would be an overkill. Also Scala, the back-end language of Datazenit, provides more flexibility and abstraction than SQL. Obviously.