Liquibase Insert computed value with multiple ids - liquibase

I am trying to insert values into a database. I think the SQL would look like this:
INSERT INTO `tb_config` (`name`, `value`, `description`, `unity_id`)
(SELECT 'new_rule', true, 'rule description', id FROM tb_unity );
However, I want to do it with Liquibase, using a changeset:
<changeSet author="Luis Sukys" id="1022" >
<insert tableName="tb_config">
<column name="name">new_rule</column>
<column name="value">false</column>
<column name="descricao">rule description</column>
<column name="unidade_id" valueComputed="SELECT id FROM tb_unity" />
</insert>
</changeSet>
I've seen the use of valueComputed but with a where clause.
The idea is that it includes one row in tb_config for each id in tb_unity.
I am actually getting a 'ValidationFailedException' from liquibase.
Any help?

I use Navicat with MySQL and when I run this code, it includes one new row int tb_config for each row in tb_unity. The field i use from tb_unity is 'id'.
If I have 05 unities in tb_unity, it must add 05 rows in tb_config, with same values, only change the unity's id.

If you try running that SQL using whatever SQL tool you use, you will see that the problem is that you do indeed need a where clause. Which row of tb_unity do you want to use the id from?

Related

How to copy the the data from one Table to another Table Using Liquibase scripts

I want to know the solution for the below Test ( to copy the the data from one Table to another Table) using Liquibase a part of Corda.
Case: As part of I want to create a new table into an existing database which has already a table called TableA (which has id, name, value columns) which has some data init, I have created a TableB (which has same id, name, value columns) and I wanted to copy the data from TableA to TableB.
For that I had used the following liquibase script as suggested here in Liquibase and In-order to test I had connected to PostgreSQL DB and connected schema called "corda_schema" which has the tables.
<changeSet author="liquibase.corda" id="update-table">
<update schemaName="corda_schema" tableName="TableB">
<column name="id" valueComputed="(SELECT id from TableA)"/>
<column name="name" valueComputed="(SELECT name from TableA)"/>
<column name="value" valueComputed="(SELECT value from TableA)"/>
</update>
</changeSet>
I was getting the following error when I tried with the Liquibase update script
Error: liquibase.corda failed
Error: schema "CORDA_SCHEMA" not found in SQL statement
If I don't given the schema name in update like this
<update tableName="TableB">
<column name="value" valueComputed="(SELECT value from TableA)"/>
</update>
the Liquibase is searching in the Public schema for TableA and I get this error:
Error: liquibase.corda failed Error: schema "PUBLIC" not found in SQL statement`
And also I tried this Liquibase script changeSet by creating the table itself I tried to update data, this changeSet is running and table is created but data is not copied.
<changeSet author="liquibase.corda" id="update-table">
<createTable schemaName = "corda_schema" tableName="TableB">
<column name="id" valueComputed= "(SELECT id FROM TableA)"/>
</createTable>
</changeSet>
Please suggest anything I am missing or any other usages that will make my test success to get the data from one table to another table.
Thanks in advance.
I would suggest to just use custom sql:
<changeSet author="liquibase.corda" id="insert-table">
<sql>
insert into corda_schema.TableB
select id,name,value from corda_schema.TableA;
</sql>
</changeSet>

LiquiBase changeset: how do build a where clause based on ANOTHER table's column

Building upon the question How to build a WHERE-clause in a LiquiBase changeset, I would like to choose the default value of a column based on the value of a column from a different table.
For instance, I have two tables, order and order_history. Pls note that we maintain all our orders in both order in order_history as well. Once an order is completed, it is removed from order table.
order has a column 'status' but we missed it on order_history, you can call it a bad design.
How do I add 'status' to order_history now, and copy the value from the corresponding order
in order table for existing data at the time of upgrade? Is there a way to do this in liquibase?
If order and order_history are connected with the foreign key, then you can just do the following:
<changeSet id="foo" author="bar">
<preConditions onFail="MARK_RAN">
<and>
<columnExists tableName="order" columnName="status"/>
<columnExists tableName="order_history" columnName="status"/>
</and>
</preConditions>
<comment>Update order_history.status with values from order.status, where order.id = order_history.order_id</comment>
<update tableName="order_history">
<column name="status" valueComputed="SELECT o.status FROM order o WHERE o.id = order_id"/>
</update>
</changeSet>
If these tables are not connected, then you may use defaultValueComputed when you're adding a new column:
<addColumn tableName="order_history">
<column name="status" type="varchar(255)" defaultValueComputed="some SQL query here"/>
</addColumn>

Adding composite unique constraint in Liquibase

I'm creating a link table which has 3 columns; id, product_id, tournament_id.
Adding a uniqueConstraint to the "id" column is trivial, but I want to ensure that any pair of (product_id, tournament_id) is unique.
The example at Liquibase.org shows
<changeSet author="liquibase-docs" id="addUniqueConstraint-example">
<addUniqueConstraint catalogName="cat"
columnNames="id, name"
constraintName="const_name"
deferrable="true"
disabled="true"
initiallyDeferred="true"
schemaName="public"
tableName="person"
tablespace="A String"/>
</changeSet>
but is it possible to accomplish this within a <createTable> block?
Also, just to confirm; does this create a composite unique constraint on the two columns, or does it create two separate unique constraints?
You can read liquibase manual also similar problem you can find here
In your case it should be:
<changeSet author="liquibase-docs" id="addUniqueConstraint-example">
<addUniqueConstraint
columnNames="product_id, tournament_id"
constraintName="your_constraint_name"
tableName="person"
/>
</changeSet>
I am pretty certain that:
You can't do it inside the createTable tag itself, but you can do it within the same changeset as when the table is created.
It does create a composite unique constraint on the two columns. One way you can check is to run liquibase with the command to generate the SQL for update rather than running the update command and check what it does for your database. On the command line, rather than running liquibase update you would run liquibase updateSQL.
In case people like myself are still asking themselves this question years later: (by now) it is possible to do this within the createTable tag itself if you provide the same name for the constraint:
<changeSet id="composite-unique-example" author="composite-unique-example">
<createTable tableName="example">
<column name="foo" type="bigint">
<constraints unique="true" uniqueConstraintName="foo-bar_unique"/>
</column>
<column name="bar" type="bigint">
<constraints unique="true" uniqueConstraintName="foo-bar_unique"/>
</column>
</createTable>
</changeSet>
Running Liquibase 4.5.0 and MySQL 5.7:
mysql> insert into example (foo, bar) values (1, 2), (2, 1), (1, 3);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from example;
+------+------+
| foo | bar |
+------+------+
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
+------+------+
3 rows in set (0.00 sec)
mysql> insert into example (foo, bar) values (1, 2);
ERROR 1062 (23000): Duplicate entry '1-2' for key 'foo-bar_unique'

Liquibase adding default value and not null constraint

I am bit new to Liquibase. I came across a scenario where in one changeSet it is trying to add a default value first and not null constraint next to that.
But problem over here is both <addDefaultValue/> and <addNotNullConstraint/> tags have a default value attributes so eventually I am ending up with an exception.
Below is the changeSet that I have,
<changeSet id="f3047816-2d48-4341-a4ce-deface083cea" author="MineStar" failOnError="true">
<preConditions onFailMessage="Ignored AlterColumn for REHANDLE of table LOCATION as column does not exist or already has a NOT NULL constraint." onFail="MARK_RAN">
<columnExists tableName="LOCATION" columnName="REHANDLE"/>
<ext:columnIsNullable tableName="LOCATION" columnName="REHANDLE"/>
</preConditions>
<comment>AHS-1373: AlterColumn LOCATION.REHANDLE - nullability changed from true to false - defaultValue changed from 'null' to '0'</comment>
<addDefaultValue columnName="REHANDLE" columnDataType="BOOLEAN" defaultValueNumeric="0" tableName="LOCATION"/>
<addNotNullConstraint columnName="REHANDLE" defaultNullValue="0" columnDataType="BOOLEAN" tableName="LOCATION"/>
</changeSet>
Here one more strange thing I could see is if I rearrange the order of adding default value and not null constraints tags I won't get any exception that is first adding not null constraint and then default value like below. But I should not do that as it effects checksum in database all that I can do is adding a new changeSet to resolve the exception.
<addNotNullConstraint columnName="REHANDLE" defaultNullValue="0" columnDataType="BOOLEAN" tableName="LOCATION"/>
<addDefaultValue columnName="REHANDLE" columnDataType="BOOLEAN" defaultValueNumeric="0" tableName="LOCATION"/>.
There is a difference between the defautlNullValue in addNotNullConstraint and defaultValueNumeric in addDefaultValue. Using addDefaultValue just sets a default value for future rows inserted into the column but defaultNullValue in addNotNullConstraint will cause liquibase to generate an additional SQL statement of update location set rehandle=0 where rehandle is null to change the value of already existing rows so that a null constraint can be added.
I would think either order would work fine, what exception were you seeing?

How to tell nHibernate not to allow duplicate entries in a table?

I have a simple entity that has an Id (the primary key) and a string name. I'm looking for a way to tell nHibernate not to allow duplicate names in the table.
I'd like to have an Add method that can take a new entity (with Id = 0), and if necessary add the new entity & update Id. This works now. If the name already exists in the table, I want to simply update Id and return the existing Id.
I'd like to be able call it like this:
Foo foo = new Foo(name); // foo.Id = 0
FooRepository.Add(foo);
.. and afterwards foo.Id <> 0 and it was either added or an existing foo.name was found and its Id was returned.
thanks/jf
You have to set the unique attribute equal to true in the mapping file in order to make this a unique column.
<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>
If you intend for the column to be a primary key for that table, then put
<id name="CommentId">
<column name="comment_id" not-null="false"/>
<generator class="identity"/>
</id>
The column will automatically have a unique constraint on it.
I dont think nhibernate can match additionally on natural key . You would have to do that in the add method in the repository .
i.e Look up by name ,if found update the name and save.( find by example might save you sometime here )
Looks like you want to use assigned id's instead of surrogate id here .
May be map name as identifier and get rid of surrogate key