I have this database in postgresql which has this index:
CREATE INDEX fav_alias_lower_index ON fav_alias USING hash((LOWER(fav_alias)));
When I reversed engineered this database I got this liquibase changelog:
<changeSet author="jmartins (generated)" id="1410448831080-17">
<createIndex indexName="workspace_favorite_alias_lower_case_index" tableName="workspace_favorite_alias" unique="false">
<column name="lower((fava_alias)::text)"/>
</createIndex>
</changeSet>
This works fine when I apply an update on a PostgreSql database, however, it doesn't work on MySql for example. So my question is how can I make this index creation available for MySql, MSSQL and Oracle too, preserving the lowercasing of fava_alias?
Thanks
If the function is available in your Database, you can use it in liquibase. There is a way to differentiate between different DBs using dbms attribute.
<changeSet author="jmartins (generated)" id="1410448831080-17">
<createIndex indexName="workspace_favorite_alias_lower_case_index" tableName="workspace_favorite_alias" unique="false" dbms="postgresql">
<column name="lower((fava_alias)::text)"/>
</createIndex>
</changeSet>
<changeSet author="jmartins (generated)" id="1410448831080-17">
<createIndex indexName="workspace_favorite_alias_lower_case_index" tableName="workspace_favorite_alias" unique="false" dbms="oracle">
<column name="lower(fava_alias)"/>
</createIndex>
</changeSet>
Related
I read a lot about the Hiberante #MapsID annotation.
hibernate tips same primary key one to one association
the best way to map a onetoone relationship with jpa and hibernate
change one to one primary key column jpa hibernate
By getting it to run the foreignkey ID of the relationship owner table seems useless and was always NULL for the column license_id.
This works when creating the table and the foreign key separately:
<changeSet author="markus" id=1">
<createTable tableName="additional_information">
<column name="id" type="int">
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_additional_information"/>
</column>
<column name="license_id" type="INTEGER" />
<column name="comment" type="nvarchar(1024) NULL" />
</createTable>
</changeSet>
<changeSet author="markus" id="2">
<addForeignKeyConstraint
constraintName="FK_ADDITIONAL_INFORMATION_ON_ID"
baseTableName="additional_information"
baseColumnNames="license_id"
referencedTableName="license"
referencedColumnNames="id" />
</changeSet>
Set primary key and foreign key to the same id seems not to work on SQL level:
The only source I found and I think I understood was that it should work I found in hibernate tips same primary key one to one association and I see it in practice. :-(
Executing this changelog:
<changeSet author="markus" id=1">
<createTable tableName="additional_information">
<column name="id" type="INTEGER">
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_additional_information"/>
</column>
<column name="comment" type="nvarchar(1024) NULL" />
</createTable>
</changeSet>
<changeSet author="markus" id="2">
<addForeignKeyConstraint
constraintName="FK_ADDITIONAL_INFORMATION_ON_ID"
baseTableName="additional_information"
baseColumnNames="id"
referencedTableName="license"
referencedColumnNames="id" />
</changeSet>
Leads to an error:
Unexpected error running Liquibase: Migration failed for changeset changelog_1.xml::2::markus:
Reason: liquibase.exception.DatabaseException: Cannot add foreign key constraint [Failed SQL: (1215) ALTER TABLE table.additional_information ADD CONSTRAINT FK_ADDITIONAL_INFORMATION_ON_ID FOREIGN KEY (id) REFERENCES table.license (id)]
Does anybody know how I can tell liquibase to use the same ID as PK and FK?
Thanks,
Markus
I'm teaching myself how to use Liquibase for MySQL database versioning and migrations.
I'm on a Spring Boot project with Maven and MySQL for handling databases.
I created a master changelog for including several changelogs file, until this point it's all good. The problem start when applying my first migration creating a simple user table with id, email, name, created and updated columns.
The migrations runs well except for one thing. Liquibase is not applying the NOT NULL for all the columns, the TIMESTAMP data type for updated nor the CURRENT_TIMESTAMP extra, and also is ignoring the unique index for the email column.
My first try was on a .xml changelog, I thought it could be the .xml format so I change it for a SQL syntax. That didn't work either. I also created the table first and later add the not null constraint and didn't work.
At this point I don't know what else to do and I can't find any more good post or documentation about it.
Note: The only "special" constraint it's applying is the primary key and auto increment and ignore all the others features.
I would be very greatful for any help I can get!
Here's my liquibase.properties:
url = jdbc:mysql://localhost/skullproject
username = skull
password = skullpass
driver = com.mysql.jdbc.Driver
Here's my migration XML changelog:
<changeSet id="1" author="f6rnando">
<createTable tableName="user">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints primaryKey="true" nullable="false" />
</column>
<column name="email" type="VARCHAR(80)">
<constraints nullable="false" />
</column>
<column name="password" type="VARCHAR(80)">
<constraints nullable="false" />
</column>
<column name="name" type="VARCHAR(80)">
<constraints nullable="false" />
</column>
<column name="updated" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP">
<constraints nullable="false" />
</column>
<column name="created" type="DATETIME">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
<changeSet author="f6rnando" id="1491156436761-3">
<addUniqueConstraint columnNames="email"
constraintName="email_UNIQUE" tableName="user" />
</changeSet>
And here's my MySQL changelog:
--liquibase formatted sql
--changeset f6rnando:1
CREATE TABLE user (
id BIGINT NOT NULL AUTO_INCREMENT,
email VARCHAR(80) NOT NULL,
password VARCHAR(80) NOT NULL,
name VARCHAR(80) NOT NULL,
updated TIMESTAMP NOT NULL DEFAULT current_timestamp,
created DATETIME NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX email_UNIQUE (email ASC)
);
--changeset f6rnando:2
ALTER TABLE user MODIFY email VARCHAR(80) NOT NULL;
--changeset f6rnando:3
ALTER TABLE user MODIFY password VARCHAR(80) NOT NULL;
After all the ways I've tried, this is always the same result:
MySQL Table info
I ran the CREATE TABLE statement on MySQL Workbench and got no problem at all. All the constraints where created just fine:
MySQL Table executed on Workbench
After a week of research and trials, the problem was a Hibernate configuration. In my application.properties file I had spring.jpa.hibernate.ddl-auto = create-drop which means according to the #Entity classes, the database is created then dropped when the SessionFactory closes. Apparently this overrides the Liquibase behavior.
To solve this problem I set the spring.jpa.hibernate.ddl-auto to none. Then Liquibase was able to behave as expected.
So I created a table named tv_campaigns in liquibase as follows.
<changeSet id=" add tv campaigns table" author="abc">
<createTable tableName="tv_campaigns">
<column name="campaign_id" type="int" autoIncrement="false">
<constraints primaryKey="true"
foreignKeyName="fk_linear_tv_campaign_id"
references="campaigns(id)"
nullable="false"/>
</column>
</createTable>
</changeSet>
Here the primary and foreign key is the same (campaign_id) and the table just have one column.
Later I realized I need an auto-increment column in this table and proceeded to add this changeset:
<changeSet id="add auto increment column" author="abc">
<addColumn tableName="tv_campaigns">
<column name="id" type="int" autoIncrement="true">
<constraints unique="true"
nullable="false"/>
</column>
</addColumn>
</changeSet>
On running this changeset I get the following error: "Cannot add a non-primary key identity column". Tried adding 'id' as a primary key by dropping the older primary key (campaign_id) and that too throws an error about foreign key relation not properly defined (as the original primary key also references another table's key).
Is there a way to do it nicely or to do it?
I believe your existing column is considered the primary key. In order to check it, see the indexes tab in HeidiSQL or similar. Some more information on the subject you can find here Add Auto-Increment ID to existing table?
The following changeset should work:
<changeSet id="1" author="Me">
<dropPrimaryKey tableName="tv_campaigns"/>
<addColumn tableName="tv_campaigns">
<column name="ID" type="bigint(20)" autoIncrement="true">
<constraints nullable="false" primaryKey="true" unique="true"/>
</column>
</addColumn>
<addAutoIncrement tableName="tv_campaigns" columnName="ID" columnDataType="bigint(20)"/>
</changeSet>
It sounds like a restriction imposed by MySQL. Which is not surprising, really. Are you able to make the same change using SQL statements? If so then it should be possible via Liquibase. But if you can't do it with SQL, then you can't do it with Liquibase either.
given the following changelog, the table "table_person" will not have an autoIncrement on its primary key column " after execution on a MySQL database.
Thus inserts on that table will fail with a message similar to: "SQL error (1062): Duplicate entry '0' for key 'PRIMARY'"
<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="201505111301" author="sr">
<createTable tableName="table_person">
<column name="table_person_id" type="int" autoIncrement="true">
<constraints primaryKey="true" nullable="false" />
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false" />
</column>
</createTable>
<insert tableName="table_person">
<column name="name" value="TestValue1" type="varchar(255)"/>
</insert>
<insert tableName="table_person">
<column name="name" value="TestValue2" type="varchar(255)"/>
</insert>
<renameColumn oldColumnName="table_person_id" newColumnName="id" tableName="table_person" columnDataType="int"/>
</changeSet>
I've tried to fix that using:
<addAutoIncrement tableName="table_person" columnName="id" columnDataType="int"></addAutoIncrement>
This will recreate the lost autoIncrement but will obviously start at index 0 again. This again leads to problems if data already exists.
My question:
How can I rename a primary key column in Liquibase without loosing the autoIncrement on the primary key for a mySQL database?
(Note, on postgreSQL the autoIncrement is not lost during rename of the primary key column)
Unfortunately it's a limitation of mysql. The SQL ran by liquibase is alter table table_person change table_persion_id id int which redefines the column as simply "int".
To keep it as auto-increment you will need to use the <modifySql> tag to <append> the auto-increment/primary key/not null/etc. information to the generated SQL as needed.
As a workaround you can use the sql tag to manually rename the column and keep the auto increment:
<sql>ALTER TABLE `pkey` CHANGE `keyfield` `keyfield2` INT( 11 ) NOT NULL AUTO_INCREMENT</sql>
Related: How do I rename a primary key column in MySQL?
I am using Liquibase for generating a MySQL and a HSQLDB databases. In several tables I have a column called 'last_modified' which is the TIMESTAMP of the last update on that particular record.
<changeSet author="bob" id="7">
<createTable tableName="myTable">
<column autoIncrement="true" name="id" type="INT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="name" type="VARCHAR(128)">
<constraints nullable="false" />
</column>
<column name="description" type="VARCHAR(512)" />
<column defaultValueBoolean="true" name="enabled" type="BIT">
<constraints nullable="false" />
</column>
<column name="last_modified" type="TIMESTAMP"/>
</createTable>
<modifySql dbms="mysql">
<append value=" engine innodb" />
</modifySql>
</changeSet>
I noticed that if I use MySQL, the generated SQL for that column is:
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
While if I use HSQLDB, in case of update nothing happens, but I would like to have the same behaviour of the MySQL database with a default value on update equals to the CURRENT_TIMESTAMP.
How can I set the CURRENT_TIMESTAMP as a default value ON UPDATE?
Or you could try this, as you have already have modifySql tag added:
<column defaultValue="CURRENT_TIMESTAMP"
name="timestamp"
type="TIMESTAMP">
<constraints nullable="false"/>
</column>
<modifySql dbms="mysql">
<regExpReplace replace="'CURRENT_TIMESTAMP'" with="CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"/>
<append value=" engine innodb" />
</modifySql>
Liquibase 3.1.1 does not produce what you described above. I have to deal with it as given above
You can't do this with a default value. The MySQL behaviour is non-standard and not supported by other databases. The proper way to do this is with a TRIGGER which is defined as BEFORE UPDATE and sets the timestamp each time the row is updated.
Update: From HSQLDB version 2.3.4 this feature is supported. For example: CREATE TABLE T1(ID INT, last_modified timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL). Note the NOT NULL constraint must appear after the DEFAULT and ON UPDATE clauses.
we actually use Liquibase for the exact same use-case. You'll want to make an update trigger as fredt described. Otherwise, you can't be sure the update will occur on other databases besides MySQL. Your changeset tag will log something like this:
<sql splitStatements="false">
CREATE TRIGGER update_${tableName}_trg
BEFORE UPDATE ON ${tableName}
FOR EACH ROW BEGIN
SET NEW.updated_at = NOW();
END
</sql>
Also, I have a question on Stack Overflow about how to refactor some of this code you can see at How do you refactor similar looking code and provide params in Liquibase?.