How to build a WHERE-clause in a LiquiBase changeset - where-clause

How do I have to define a changeset in 'LiquiBase' notation for updating a table column whith an AND-ed WHERE-clause:
<changeSet id="ddl update tables : modify datatype for MY_TABLE.STATE_ABBREV" author="xxx">
<preConditions onFail="MARK_RAN" onFailMessage="Column MY_TABLE.STATE_ABBREV doesn't exists.">
<and>
<tableExists tableName="MY_TABLE"/>
<columnExists tableName="MY_TABLE" columnName="STATE_ABBREV"/>
</and>
</preConditions>
<update tableName="MY_TABLE">
<column name="STATE_ABBREV" value="AS"/>
<where>AGU /***AND STATE_ID=3***/ ??????????????????
</where>
</update>
</changeSet>

What you put in the <where> tag is simply appended to the end of the UPDATE statement after a " WHERE ". You can put anything in the where tag that you would normally put in SQL.
Example:
<changeSet id="ddl update tables : modify datatype for MY_TABLE.STATE_ABBREV" author="xxx">
<preConditions onFail="MARK_RAN" onFailMessage="Column MY_TABLE.STATE_ABBREV doesn't exists.">
<and>
<tableExists tableName="MY_TABLE"/>
<columnExists tableName="MY_TABLE" columnName="STATE_ABBREV"/>
</and>
</preConditions>
<update tableName="MY_TABLE">
<column name="STATE_ABBREV" value="AS"/>
<where>STATE_ABBREV IS NULL AND STATE_ID=3</where>
</update>
</changeSet>

Related

liquibase agnostic insert with sequence

I want to create a new insert changeset in liquibase using a sequence to populate the id field. Is there any way to make it database agnostic for Oracle an Postgres?
This is the oracle way:
<changeSet author="XX" id="XX">
<insert tableName="NODO_MENU">
<column name="ID" defaultValueSequenceNext="SEQ_NODO_MENU" />
<column name="CODIGO" value="ABC" />
<column name="ORDEN" value="0" />
</insert>
<rollback>
<delete tableName="NODO_MENU">
<where>CODIGO = 'ABC'</where>
</delete>
</rollback>
</changeSet>
It doesn´t work in postgres:
[Failed SQL: INSERT INTO public.NODO_MENU (ID, CODIGO, ORDEN) VALUES (SEQ_NODO_MENU.NEXTVAL, 'ABC', '0')]
To make it work in postgres I changed the column tag to:
<column name="ID" valueComputed="nextval('SEQ_NODO_MENU')" />
How can i write this changeset to make it work in Oracle an Postgress?
You can write two separate changesets. One for Postgres, one for Oracle.
Just add corresponding dbms preConditions to them.
As such:
<changeSet author="XX" id="XX_oracle">
<preConditions onFail="MARK_RAN">
<dbms type="oracle"/>
</preConditions>
<!-- your logic for Oracle-->
</changeSet>
<changeSet author="XX" id="XX_postgres">
<preConditions onFail="MARK_RAN">
<dbms type="postgresql"/>
</preConditions>
<!-- your logic for Postrgres-->
</changeSet>

Set initial value in liquibase with postgresql database

I have a table and i need that it's ID start in 1000000.
I have this code set for liquibase:
<column name="id" type="bigint" autoIncrement="true" startWith="1000000">
<constraints primaryKey="true" nullable="false"/>
</column>
But it does not work in postgres, the generated sequence generator starts with 1.
Does anyone has any idea on this? How can i enable a table to start from a value in liquibase that works with postgresql?
Thanks in advance!
just alterSequence won't help:
<alterSequence
minValue="1000000"
sequenceName="t1_id_seq"/>
Unexpected error running Liquibase: ERROR: START value (1) cannot be
less than M INVALUE (1000000) [Failed SQL: ALTER SEQUENCE
public.t1_id_seq MINVALUE 1000000]
and according to docs you can't start sequence with alterSequence, so you have to createSequence with
<createSequence
sequenceName="seq_id"
startValue="1000000"/>
and then "assign" it as default value to your bigint column
<sql dbms="postgresql" endDelimiter=";\n" splitStatements="true"
stripComments="true">ALTER TABLE t1 ALTER COLUMN id SET DEFAULT nextval('seq_id');
</sql>
or initially use bigserial and sql to restart sequence:
<changeSet author="Vao" id="1">
<createTable tableName="t2">
<column name="id" type="bigserial">
<constraints primaryKey="true" primaryKeyName="t2_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Vao" id="2">
<sql dbms="postgresql" endDelimiter=";">ALTER SEQUENCE t2_id_seq restart with 1000;
</sql>
</changeSet>
Unfortunately startWith don't seems to work for postgres db.
You can use (with yaml configuration) :
- changeSet:
id: add-auto-increment-postgres
author: me
dbms: postgresql
changes:
- createSequence:
sequenceName: my_sequence
startValue: 1000
- addDefaultValue:
columnName: id
defaultValueSequenceNext: my_sequence
tableName: my_table
Thx! Drop and create new - helps
dropSequence
createSequence

Liquibase: Copy column data into a new column in the same table

I have a table with a column A. I am creating a new column B. B will have the same data as column A. How do I replicate the column in Liquibase? Is there some expression I can write to do the replication?
this is possible too:
<changeSet id="1" author="your_name">
<addColumn tableName="your_table">
<column name="b" type="varchar(255)"/>
</addColumn>
</changeSet>
<changeSet id="2" author="your_name">
<update tableName="your_table">
<column name="b" valueComputed="a"/>
</update>
</changeSet>
Create a new changeset where you add a new column, and then update column B using the <sql> tag:
<changeSet author="yourName" id="example">
<addColumn catalogName="db"
schemaName="public"
tableName="yourTable">
<!-- replace varchar(255) with the actual type of column A -->
<column name="B" type="varchar(255)"/>
</addColumn>
<sql>UPDATE yourTable SET B = A</sql>
</changeSet>

Does LiquiBase generate invalid SQL?

For my MySql database I have a LiquiBase changeset that looks like this:
<changeSet id="ddl update tables : modify datatype for MY_TABLE.STATE_ABBREV" author="xxx">
<preConditions onFail="MARK_RAN" onFailMessage="Column MY_TABLE.STATE_ABBREV doesn't exists.">
<and>
<tableExists tableName="MY_TABLE"/>
<columnExists tableName="MY_TABLE" columnName="STATE_ABBREV"/>
</and>
</preConditions>
<update tableName="MY_TABLE">
<column name="STATE_ABBREV" value="AS"/>
<where>AGU
</where>
</update>
</changeSet>
This will result in
UPDATE MY_TABLE SET STATE_ABBREV = 'AS' WHERE AGU;
This does not look like valid ANSI SQL. Is this a LiquiBase bug or does LiquiBase do anything with this SQL before submitting to the database?
How can I tell LiquiBase to generate well-formed ANSI SQL?

Convert int to value when changing datatype in column

Is it possible with liquibase to do some kind of mapping when doing a modifyDataType?
Considering the following example:
<changeSet id="1" author="me">
<createTable tableName="person">
<column name="id" type="int">
<constraints primaryKey="true" nullable="false" />
</column>
<column name="firstName" type="varchar(100)"></column>
<column name="lastName" type="varchar(100)"></column>
<column name="marital_status" type="int">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
<changeSet id="2" author="me">
<modifyDataType tableName="person" columnName="type"
newDataType="varchar(36)" />
</changeSet>
I would like in my column 'type' that the following mapping occurs:
0->single
1->married
etc..
Is this possible with liquibase? I'm using it via the command line.
I think this is not possible directly via some kind of mapping or refactoring.
One way to do this is using sql and put this into another changeset which is run right after the one that changes the data type:
<changeSet id="3" author="me">
<sql>
update person set martial_status = 'single' where martial_status = 0;
update person set martial_status = 'married' where martial_status = 1;
</sql>
</changeSet>
I just wrote this down as an idea. It is untested.
You could add a precondition to execute this changeset only if changeset with id 2 ran successful.