Using SQLcl Liquibase

This post summarizes the most useful SQLcl Liquibase commands and how they can be used. The output of the commands are shown as well.

Overview

Liquibase is a database schema change management tool that helps developers track, version, and deploy database changes in a controlled and consistent way. It allows teams to automate database updates, rollbacks, and migrations across different environments (e.g., development, testing, production).

Environment

  • Oracle 19.3

Using Liquibase

Capture and deploy a single table:

-- connect to the source schema
conn -n win3_orcl_user1
create table t as select * from all_source where 1=0;
desc t
-- Capture table t, overwrite existing xml files (-ovf)
lb generate-db-object -ovf -obt table -obn t
-- connect to the destination schema
conn -n win3_orcl_user2
desc t
-- Deploy the object in another schema
lb update -changelog-file t_table.xml
desc t
-- add a column to the source table t
conn -n win3_orcl_user1
alter table t add (newcolumn number);
-- capture the changes to table t into a new changelog file
lb geo -obt table -ovf -obn t
-- apply the change to user2.t
conn -n win3_orcl_user2
lb update -changelog-file t_table.xml
desc t
Screen Output (click):
SQL> -- connect to the source schema
SQL> conn -n win3_orcl_user1
Connected.
SQL> create table t as select * from all_source where 1=0;

Table T created.

SQL> desc t

Name             Null?    Type
________________ ________ _________________
OWNER                     VARCHAR2(128)
NAME                      VARCHAR2(128)
TYPE                      VARCHAR2(12)
LINE                      NUMBER
TEXT                      VARCHAR2(4000)
ORIGIN_CON_ID             NUMBER
SQL> -- Capture table t, overwrite existing xml files (-ovf)
SQL> lb generate-db-object -ovf -obt table -obn t
--Starting Liquibase at 2025-07-20T16:08:07.752148600 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Changelog created and written out to file t_table.xml

Operation completed successfully.

SQL> -- connect to the destination schema
SQL> conn -n win3_orcl_user2
Connected.
SQL> desc t

ERROR:
ORA-04043: object t does not exist
SQL> -- Deploy the object in another schema
SQL> lb update -changelog-file t_table.xml
--Starting Liquibase at 2025-07-20T16:08:09.219823400 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Running Changeset: t_table.xml::37399abaae1ee767cb1084484729d0e4a0b9c6da::(USER1)-Generated
Table "T" created.

UPDATE SUMMARY
Run:                          1
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            1

Liquibase: Update has been successful. Rows affected: 1


Operation completed successfully.

SQL> desc t

Name             Null?    Type
________________ ________ _________________
OWNER                     VARCHAR2(128)
NAME                      VARCHAR2(128)
TYPE                      VARCHAR2(12)
LINE                      NUMBER
TEXT                      VARCHAR2(4000)
ORIGIN_CON_ID             NUMBER
SQL> -- add a column to the source table t
SQL> conn -n win3_orcl_user1
Connected.
SQL> alter table t add (newcolumn number);

Table T altered.

SQL> -- capture the changes to table t into a new changelog file
SQL> lb geo -obt table -ovf -obn t
--Starting Liquibase at 2025-07-20T16:08:13.998278100 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Changelog created and written out to file t_table.xml

Operation completed successfully.

SQL> -- apply the change to user2.t
SQL> conn -n win3_orcl_user2
Connected.
SQL> lb update -changelog-file t_table.xml
--Starting Liquibase at 2025-07-20T16:08:15.058325600 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Running Changeset: t_table.xml::b923121747e8e49f504d399b58e46243e7aa49d7::(USER1)-Generated
Table "T" altered.

UPDATE SUMMARY
Run:                          1
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            1

Liquibase: Update has been successful. Rows affected: 1


Operation completed successfully.

SQL> desc t

Name             Null?    Type
________________ ________ _________________
OWNER                     VARCHAR2(128)
NAME                      VARCHAR2(128)
TYPE                      VARCHAR2(12)
LINE                      NUMBER
TEXT                      VARCHAR2(4000)
ORIGIN_CON_ID             NUMBER
NEWCOLUMN                 NUMBER
SQL>

Capture and deploy a complete schema

conn -n win3_orcl_user1
-- create a second table
create table t2 as select * from t where 1=0;
-- Capture the complete schema
lb ges
-- Deploy the changelog file to user2
conn -n win3_orcl_user2
lb update -chf controller.xml
select table_name from user_tables;
Sample Output (click):
SQL> conn -n win3_orcl_user1
Connected.
SQL> -- create a second table
SQL> create table t2 as select * from t where 1=0;

Table T2 created.

SQL> -- Capture the complete schema
SQL> lb ges
--Starting Liquibase at 2025-07-20T16:13:57.610030300 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)

Export Flags Used:

Export Grants           false
Export Synonyms         false

[Method loadCaptureTable]:
        [Type - TYPE_SPEC]:                        355 ms
        [Type - TYPE_BODY]:                        174 ms
        [Type - SEQUENCE]:                          61 ms
        [Type - DIRECTORY]:                         54 ms
        [Type - CLUSTER]:                         1966 ms
        [Type - TABLE]:                          18251 ms
        [Type - MATERIALIZED_VIEW_LOG]:             63 ms
        [Type - MATERIALIZED_VIEW]:                 37 ms
        [Type - VIEW]:                            3837 ms
        [Type - REF_CONSTRAINT]:                   196 ms
        [Type - DIMENSION]:                         62 ms
        [Type - PACKAGE_SPEC]:                     113 ms
        [Type - FUNCTION]:                         107 ms
        [Type - PROCEDURE]:                        106 ms
        [Type - DB_LINK]:                           63 ms
        [Type - SYNONYM]:                           77 ms
        [Type - INDEX]:                           3097 ms
        [Type - TRIGGER]:                          379 ms
        [Type - PACKAGE_BODY]:                     152 ms
        [Type - JOB]:                               71 ms

[Method loadCaptureTable]:                       29221 ms
[Method sortCaptureTable]:                          40 ms
[Method writeChangeLogs]:                           14 ms
Changelog created and written out to file controller.xml

Operation completed successfully.

SQL> -- Deploy the changelog file to user2
SQL> conn -n win3_orcl_user2
Connected.
SQL> lb update -chf controller.xml
--Starting Liquibase at 2025-07-20T16:14:28.420219 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Running Changeset: t2_table.xml::fbbba76b8e2f2f49a75698fd600155c8ebb2fb38::(USER1)-Generated
Table "T2" created.

UPDATE SUMMARY
Run:                          1
Previously run:               1
Filtered out:                 0
-------------------------------
Total change sets:            2

Liquibase: Update has been successful. Rows affected: 1


Operation completed successfully.

SQL> select table_name from user_tables;

TABLE_NAME
____________________________
DATABASECHANGELOG_ACTIONS
DATABASECHANGELOG
DATABASECHANGELOGLOCK
T
T2

5 rows selected.

SQL>

Rollback to a previous version

conn -n win3_orcl_user2
select table_name from user_tables;
-- tag the current version
lb ta -ta before_change
-- make and deploy a change
conn -n win3_orcl_user1
create table t3 as select * from t where 1=0;
lb ges
conn -n win3_orcl_user2
lb update -chf controller_1.xml
select table_name from user_tables;
-- rollback to the previous version
lb rb -chf controller_1.xml -ta before_change
select table_name from user_tables;
Sample Output (click):
SQL> conn -n win3_orcl_user2
Connected.
SQL> select table_name from user_tables;

TABLE_NAME
____________________________
DATABASECHANGELOG_ACTIONS
DATABASECHANGELOG
DATABASECHANGELOGLOCK
T
T2

5 rows selected.

SQL> -- tag the current version
SQL> lb ta -ta before_change
--Starting Liquibase at 2025-07-20T16:22:27.651142800 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Successfully tagged 'USER2@jdbc:oracle:thin:@win3.fritz.box:1521/orcl.fritz.box'


Operation completed successfully.

SQL> -- make and deploy a change
SQL> conn -n win3_orcl_user1
Connected.
SQL> create table t3 as select * from t where 1=0;

Table T3 created.
SQL> lb ges
--Starting Liquibase at 2025-07-20T16:22:29.378403200 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)

Export Flags Used:

Export Grants           false
Export Synonyms         false

[Method loadCaptureTable]:
        [Type - TYPE_SPEC]:                         99 ms
        [Type - TYPE_BODY]:                         69 ms
        [Type - SEQUENCE]:                          61 ms
        [Type - DIRECTORY]:                         33 ms
        [Type - CLUSTER]:                           55 ms
        [Type - TABLE]:                          18006 ms
        [Type - MATERIALIZED_VIEW_LOG]:             62 ms
        [Type - MATERIALIZED_VIEW]:                 36 ms
        [Type - VIEW]:                            3192 ms
        [Type - REF_CONSTRAINT]:                   198 ms
        [Type - DIMENSION]:                         62 ms
        [Type - PACKAGE_SPEC]:                      50 ms
        [Type - FUNCTION]:                          53 ms
        [Type - PROCEDURE]:                         51 ms
        [Type - DB_LINK]:                           40 ms
        [Type - SYNONYM]:                           41 ms
        [Type - INDEX]:                             64 ms
        [Type - TRIGGER]:                           42 ms
        [Type - PACKAGE_BODY]:                      71 ms
        [Type - JOB]:                               73 ms

[Method loadCaptureTable]:                       22358 ms
[Method sortCaptureTable]:                          23 ms
[Method writeChangeLogs]:                           28 ms
Changelog created and written out to file controller_1.xml

Operation completed successfully.

SQL> conn -n win3_orcl_user2
Connected.
SQL> lb update -chf controller_1.xml
--Starting Liquibase at 2025-07-20T16:22:53.006321300 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Running Changeset: t3_table.xml::ae261bebfc52f1baa82c17a68e2c95eb22fbacf3::(USER1)-Generated
Table "T3" created.

UPDATE SUMMARY
Run:                          1
Previously run:               2
Filtered out:                 0
-------------------------------
Total change sets:            3

Liquibase: Update has been successful. Rows affected: 1


Operation completed successfully.

SQL> select table_name from user_tables;

TABLE_NAME
____________________________
DATABASECHANGELOG_ACTIONS
DATABASECHANGELOG
DATABASECHANGELOGLOCK
T
T2
T3

6 rows selected.
SQL> -- rollback to the previous version
SQL> lb rb -chf controller_1.xml -ta before_change
--Starting Liquibase at 2025-07-20T16:22:55.052740100 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Rolling Back Changeset: t3_table.xml::ae261bebfc52f1baa82c17a68e2c95eb22fbacf3::(USER1)-Generated
Table "T3" dropped.


Operation completed successfully.

SQL> select table_name from user_tables;

TABLE_NAME
____________________________
DATABASECHANGELOG_ACTIONS
DATABASECHANGELOG
DATABASECHANGELOGLOCK
T
T2

5 rows selected.
SQL>

Include table data in the capture and deploy

-- create a table and data
conn -n win3_orcl_user1
drop table t;
create table t (a number);
insert into t values (1);
commit;
select count(*) from t;
-- generate changelog files
lb generate-db-object -ovf -obt table -obn t
lb da -ino t -ouf t_data.xml -ovf

conn -n win3_orcl_user2
-- drop all objects in the target schema
lb drop-all
-- create the table and insert data
lb update -changelog-file t_table.xml
lb up -chf t_data.xml
select count(*) from t;
Sample Output (click):
SQL> -- create a table and data
SQL> conn -n win3_orcl_user1
Connected.
SQL> drop table t;

Table T dropped.

SQL> create table t (a number);

Table T created.

SQL> insert into t values (1);

1 row inserted.

SQL> commit;

Commit complete.

SQL> select count(*) from t;

   COUNT(*)
___________
          1

1 row selected.

SQL> -- generate changelog files
SQL> lb generate-db-object -ovf -obt table -obn t
--Starting Liquibase at 2025-07-20T16:25:36.247148900 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Changelog created and written out to file t_table.xml

Operation completed successfully.

SQL> lb da -ino t -ouf t_data.xml -ovf
--Starting Liquibase at 2025-07-20T16:25:36.627796400 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
BEST PRACTICE: The changelog generated by diffChangeLog/generateChangeLog should be inspected for correctness and completeness before being deployed. Some database objects and their dependencies cannot be represented automatically, and they may need to be manually updated before being deployed.
Command completed successfully please review file c:/sw/sqlcl/bin/t_data.xml

Operation completed successfully.

SQL>
SQL> conn -n win3_orcl_user2
Connected.
SQL> -- drop all objects in the target schema
SQL> lb drop-all
--Starting Liquibase at 2025-07-20T16:25:38.815844600 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
INFO: The drop-all command may result in unrecoverable destructive changes to objects at 'jdbc:oracle:thin:@win3.fritz.box:1521/orcl.fritz.box'.
To protect against unwanted drops, set --requireForce=true, which will require a --force=true flag on the command.
Learn more at https://docs.liquibase.com/dropall.

All objects dropped from USER2@jdbc:oracle:thin:@win3.fritz.box:1521/orcl.fritz.box


Operation completed successfully.

SQL> -- create the table and insert data
SQL> lb update -changelog-file t_table.xml
--Starting Liquibase at 2025-07-20T16:26:06.298589500 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Running Changeset: t_table.xml::6208a66ed33d5914197245d5dd723a25496e3de0::(USER1)-Generated
Table "T" created.

UPDATE SUMMARY
Run:                          1
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            1

Liquibase: Update has been successful. Rows affected: 1


Operation completed successfully.

SQL> lb up -chf t_data.xml
--Starting Liquibase at 2025-07-20T16:26:10.122801400 using Java 17.0.11 (version 4.30.0 #0 built at 2025-04-01 10:24+0000)
Running Changeset: t_data.xml::1753021537705-1::User1 (generated)

UPDATE SUMMARY
Run:                          1
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            1

Liquibase: Update has been successful. Rows affected: 2


Operation completed successfully.

SQL> select count(*) from t;

   COUNT(*)
___________
          1

1 row selected.
SQL>

Cleaning up

These commands clean up the changes done by the previous examples.

conn -n win3_orcl_user2
lb drop-all
conn -n win3_orcl_user1
drop table t;
drop table t2;
drop table t3;

The .xml files can also be deleted.

More information