How to Update a Database table column to constraint nullable='true' | Liquibase - liquibase

In liquibase, I created a table, one of column is like below
<column name="identifier" type=""varchar2(50)">
<constraint nullable="false"/>
</column>
This changeset is already executed
Now I need to set this column as
<constraint nullable="true"/>
I am using MySql

If you want to change a column to nullable='true' in Liquibase, you can use the modifyColumn tag.
<modifyColumn tableName="table_name">
<column name="identifier" type="varchar2(50)">
<constraint nullable="true"/>
</column>
</modifyColumn>
Note: in Mysql, the equivalent for varchar2 is varchar; So ur modifyColumn tag should look like this:
<modifyColumn tableName="table_name">
<column name="identifier" type="varchar(50)">
<constraint nullable="true"/>
</column>
</modifyColumn>

<modifyDataType
tableName="unspecified"
columnName="identifier"
newDataType="VARCHAR(50) NOT NULL"/>

Related

Liquibase Insert computedvalue with sql multiple row

I want to insert multiple rows to the xxx_table with liquibase.
<changeSet id="XXX" author="XXX">
<comment>Add default values to xxx_table table</comment>
<insert tableName="xxx_table">
<column name="group_id"
valueComputed="(SELECT group_id FROM subscriber)"/>
<column name="business_name"
valueComputed="(SELECT business_name FROM subscriber)"/>
<column name="created_stamp" valueComputed="CURRENT_TIMESTAMP"/>
<column name="last_updated_stamp" valueComputed="CURRENT_TIMESTAMP"/>
</insert>
<rollback/>
</changeSet>
Liquibase script fails because more than one row is returned from '(SELECT business name FROM subscriber)'. How can I insert multiple raw to a table?

Hibernate Envers + Liquibase: NULL not allowed for column "REV"

I want to add Liquibase to an application that already uses Hibernate Envers, but with auto creation of the database tables. Hence, I need to write Liquibase changesets that contain the tables for my entities and the table needed for Envers.
Here's the changeset:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<property name="long_type" value="bigint" dbms="postgresql"/>
<property name="long_type" value="long" dbms="h2"/>
<changeSet id="CreateBasicSchema" author="Steven Schwenke">
<createSequence sequenceName="hibernate_sequence" startValue="0" incrementBy="1"/>
<createTable tableName="revinfo">
<column name="rev" type="integer">
<constraints primaryKey="true"/>
</column>
<column name="revtstmp" type="bigint"/>
</createTable>
<createTable tableName="stuff">
<column name="id" type="${long_type}">
<constraints nullable="false" unique="true" primaryKey="true"/>
</column>
<column name="text" type="varchar(36)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="stuff_aud">
<column name="id" type="${long_type}">
<constraints nullable="false" unique="true" primaryKey="true"/>
</column>
<column name="rev" type="integer">
<constraints referencedTableName="revinfo"
foreignKeyName="fk_brands_stuff_revinfo"
referencedColumnNames="rev"
nullable="false"/>
</column>
<column name="revtype" type="integer">
<constraints nullable="false"/>
</column>
<column name="stuff" type="varchar(36)">
<constraints nullable="true"/>
</column>
</createTable>
</changeSet>
This causes the following exception:
o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23502, SQLState: 23502
o.h.engine.jdbc.spi.SqlExceptionHelper : NULL nicht zulässig für Feld "REV"
NULL not allowed for column "REV"; SQL statement:
/* insert org.hibernate.envers.DefaultRevisionEntity */ insert into revinfo (rev, revtstmp) values (null, ?) [23502-200]
org.springframework.dao.DataIntegrityViolationException: could not execute statement ...
After some research, I finally found my error and will post it as the answer to this question. Hope that this helps other developers encountering the same exception.
The missing part is a simple autoIncrement for the ID of the revinfo table:
<createTable tableName="revinfo">
<column name="rev" type="integer" autoIncrement="true">
<constraints primaryKey="true"/>
</column>
<column name="revtstmp" type="bigint"/>
</createTable>
Without this, new entries in the revinfo table will have a null ID, which is exactly what the exception says.
Another error in the liquibase code above is that the id of the aud-table has a primary key just on id. This will lead to exceptions when updating entities. According to Vlad Mihalcea, there should be a combined key for the aud table:
<createTable tableName="stuff_aud">
<column name="id" type="${long_type}">
<constraints nullable="false" />
</column>
<column name="rev" type="integer">
<constraints referencedTableName="revinfo"
foreignKeyName="fk_brands_stuff_revinfo"
referencedColumnNames="rev"
nullable="false"/>
</column>
<column name="revtype" type="integer">
<constraints nullable="false"/>
</column>
<column name="stuff" type="varchar(36)">
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey tableName="stuff_aud" columnNames="id, rev" />

How add specific type column by liqiubase

Postgresql has type INTERVAL for column. But I didn`t found simple way to create table with such column.
I have solution with two steps:
1. Create table by liquibase changeSet.
2. Use changeSet with sqlFile. Sql file contain sql for add column.
Example changeSet:
<changeSet author="author" id="add-testmy-table-v1">
<preConditions onFail="MARK_RAN">
<not>
<tableExists tableName="testmy"/>
</not>
</preConditions>
<createTable tableName="testmy">
<column autoIncrement="true" name="id" type="BIGSERIAL">
<constraints primaryKey="true" primaryKeyName="PK_testmy"/>
</column>
<column name="created_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
<column name="employee_id" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="liquibase-docs" id="sql-example">
<sqlFile dbms="postgresql" encoding="utf8" path="testmy.sql" relativeToChangelogFile="true"/>
</changeSet>
testmy.sql file contain:
ALTER TABLE testmy
ADD COLUMN began_at INTERVAL ,
ADD COLUMN ended_at INTERVAL ;
Could anyone show another variant to solve such problem?

Liquibase createIndex column order

I'm trying to use Liquibase for our project. We mainly use Oracle database and some other database less often. I'm trying to figureout how to specify column order in case of indexes. Below is a typical create index change set.
<createIndex indexName="PK_xxxxxxx" tableName="xxxxx" unique="true">
<column name="column_1"/>
<column name="column_2"/>
<column name="column_3"/>
</createIndex>
When it comes to performance and application scalablity, column order in index matters a lot. Can you please guide me if there is a way to specify same while creating index?
PS: As per column tag documentation, attributes afterColumn, position exists and they are applicable only for create table I assume. Here is what documentation says about it.
If used in an 'addColumn' command, this attribute allows you to control where in the table column order the new column goes. Only one of beforeColumn, afterColumn or position are allowed. Since 3.1
Liquibase will use the order of columns as listed in the createIndex tag - very much like the DBMS uses the order specified in the create index statement.
The following changeset:
<changeSet author="arthur" id="1">
<createTable tableName="foo">
<column name="col_1" type="integer"/>
<column name="col_2" type="integer"/>
<column name="col_3" type="integer"/>
</createTable>
<createIndex indexName="ix_one" tableName="foo">
<column name="col_1"/>
<column name="col_2"/>
<column name="col_3"/>
</createIndex>
<createIndex indexName="ix_two" tableName="foo">
<column name="col_3"/>
<column name="col_2"/>
<column name="col_1"/>
</createIndex>
<createIndex indexName="ix_three" tableName="foo">
<column name="col_2"/>
<column name="col_3"/>
<column name="col_1"/>
</createIndex>
</changeSet>
will produce the following statements (when e.g. run with updateSQL):
CREATE TABLE public.foo (col_1 INT, col_2 INT, col_3 INT);
CREATE INDEX ix_one ON public.foo(col_1, col_2, col_3);
CREATE INDEX ix_two ON public.foo(col_3, col_2, col_1);
CREATE INDEX ix_three ON public.foo(col_2, col_3, col_1);

Liquibase: managing Master Data

I am using liquibase in my project.
I have tenant table with tenant_id as primary key. And the remaining tables have tenant_id as a column.
Now what will be the better way to handle master data with different tenants
Tables:
<createTable tableName="tenant">
<column name="tenant_id" autoIncrement="true" type="int">
<constraints primaryKey="true" nullable="false"
primaryKeyName="pk_tenant_id" />
</column>
<column name="name" type="varchar(100)"></column>
</createTable>
<createTable tableName="base_entity">
<column name="base_entity_id" autoIncrement="true" type="int">
<constraints primaryKey="true" nullable="false"
primaryKeyName="pk_base_entity_id" />
</column>
<column name="tenant_id" type="int">
<constraints nullable="false" />
</column>
</createTable>
-- Data: --
Currently I am handling data like this
<property name="#tenant_id_1"
value="(select tenant_id from tenant where name='test1') " dbms="mysql" />
<property name="#tenant_id_2"
value="(select tenant_id from tenant where name='test2') " dbms="mysql" />
<insert tableName="tenant">
<column name="name">test1</column>
</insert>
<insert tableName="tenant">
<column name="name">test2</column>
</insert>
<insert tableName="base_entity">
<column name="name">testBase_Entity</column>
<column name="tenant_id" valueComputed="${#tenant_id_1}" />
</insert>
<insert tableName="base_entity">
<column name="name">testBase_Entity</column>
<column name="tenant_id" valueComputed="${#tenant_id_2}" />
</insert>
But I have 'n' no of tenants, for every entry of tenant I've to insert the data.
Is there any option in liquibase do this in a better way ?
Thanks in advance.