Java 液化,在Oracle中创建外键,前提条件
我有一个应用程序的生产和QA实例,我正在将Liquibase集成到其中。这意味着DDL和数据已经存在或不存在(如果在开发框中)。我必须创建一个changeLog,它记录在非空DBs上运行的所有内容,但实际上在空DBs上执行。 我在一个很好的方法,但我有点坚持创建外键。数据库是Oracle 一般来说,我创建的前提条件期望各种对象不存在,一旦失败,MARK_就会运行更改 当我不知道外键的确切名称(可能存在也可能不存在)时,我发现很难编写正确的前提条件。 liquibase前提条件中有标记,但它只接受schemaName和foreignKeyName属性,并且它们是必需的。在这些情况下,我不能确定外键的名称,因为它们超出了我的控制范围 您可以在以下前提条件下编写自定义SQL:Java 液化,在Oracle中创建外键,前提条件,java,sql,database,oracle,liquibase,Java,Sql,Database,Oracle,Liquibase,我有一个应用程序的生产和QA实例,我正在将Liquibase集成到其中。这意味着DDL和数据已经存在或不存在(如果在开发框中)。我必须创建一个changeLog,它记录在非空DBs上运行的所有内容,但实际上在空DBs上执行。 我在一个很好的方法,但我有点坚持创建外键。数据库是Oracle 一般来说,我创建的前提条件期望各种对象不存在,一旦失败,MARK_就会运行更改 当我不知道外键的确切名称(可能存在也可能不存在)时,我发现很难编写正确的前提条件。 liquibase前提条件中有标记,但它只接受
<changeSet id="1" author="bob">
<preConditions onFail="WARN">
<sqlCheck expectedResult="0">select count(*) from oldtable</sqlCheck>
</preConditions>
<dropTable tableName="oldtable"/>
</changeSet>
如果MY_表中引用MY_OTHER_表的MY_列上存在外键,则会打印一行。在将其重写为COUNT之后,您可以在不知道其名称的情况下检查是否存在外键
我的问题:
我有几十个外键,我真的要写这么大的SQL几十次吗?有什么建议吗,比如把这个外包给某个职能部门?谢谢
是否值得要求Liquibase开发人员将的name属性设置为可选,并在本地列名中引入referenced table属性?如果您不知道外键约束名称,我认为您必须按照您的建议执行此操作 但若您可以修改数据库,那个么您可以准备sql脚本,该脚本将准备另一个sql脚本,该脚本将所有FK重命名为已知名称。诸如此类:
BEGIN
FOR cur IN (
SELECT
c_list.CONSTRAINT_NAME as FK_NAME,
'FK_' || c_dest.TABLE_NAME || '_' || substr(c_dest.COLUMN_NAME, 1, 20) as NEW_FK_NAME,
c_src.TABLE_NAME as SRC_TABLE,
c_src.COLUMN_NAME as SRC_COLUMN,
c_dest.TABLE_NAME as DEST_TABLE,
c_dest.COLUMN_NAME as DEST_COLUMN
FROM ALL_CONSTRAINTS c_list, ALL_CONS_COLUMNS c_src, ALL_CONS_COLUMNS c_dest
WHERE c_list.CONSTRAINT_NAME = c_src.CONSTRAINT_NAME
AND c_list.R_CONSTRAINT_NAME = c_dest.CONSTRAINT_NAME
AND c_list.CONSTRAINT_TYPE = 'R'
AND c_src.TABLE_NAME IN ('<your-tables-here>')
GROUP BY c_list.CONSTRAINT_NAME, c_src.TABLE_NAME, c_src.COLUMN_NAME, c_dest.TABLE_NAME, c_dest.COLUMN_NAME;
) LOOP
-- Generate here SQL commands (by string concatenation) something like:
-- alter table SRC_TABLE rename constraint FK_NAME to NEW_FK_NAME;
-- then paste this sql commands to some other script and run it
END LOOP;
END;
这是一次性迁移
迁移之后,您知道FK约束名称是什么,并且可以在变更集中使用前置条件。还有一种可能性:实现接口并将其用作自定义前置条件。更多信息: 以下是已验证的实现:
import liquibase.database.Database;
import liquibase.exception.CustomPreconditionErrorException;
import liquibase.exception.CustomPreconditionFailedException;
import liquibase.precondition.CustomPrecondition;
import liquibase.snapshot.SnapshotGeneratorFactory;
import liquibase.structure.core.ForeignKey;
import liquibase.structure.core.Schema;
import liquibase.structure.core.Table;
import liquibase.util.StringUtils;
/**
* {@link CustomPrecondition} implementation that checks if a column on a table
* has a foreign key constraint for some other table.
*/
public final class CheckForeignKey implements CustomPrecondition {
/**
* Schema.
*/
private String schemaName;
/**
* Table name (that has the column).
*/
private String tableName;
/**
* Column (that might have the foreign key).
*/
private String columnName;
/**
* Referenced table of the foreign key.
*/
private String foreignTableName;
@Override
public void check(final Database db)
throws CustomPreconditionFailedException,
CustomPreconditionErrorException {
try {
// The fkey we are looking for
final ForeignKey fKey = new ForeignKey();
// Schema, base table
fKey.setForeignKeyTable(new Table());
if (StringUtils.trimToNull(getTableName()) != null) {
fKey.getForeignKeyTable().setName(getTableName());
}
final Schema schema = new Schema();
schema.setName(getSchemaName());
fKey.getForeignKeyTable().setSchema(schema);
// Base column
fKey.addForeignKeyColumn(getColumnName());
// Referenced table
fKey.setPrimaryKeyTable(new Table());
if (StringUtils.trimToNull(getForeignTableName()) != null) {
fKey.getPrimaryKeyTable().setName(getForeignTableName());
}
if (!SnapshotGeneratorFactory.getInstance().has(fKey, db)) {
throw new CustomPreconditionFailedException(
String.format(
"Error fkey not found schema %s table %s column %s ftable %s",
getSchemaName(), getTableName(),
getColumnName(), getForeignTableName()));
}
} catch (final CustomPreconditionFailedException e) {
throw e;
} catch (final Exception e) {
throw new CustomPreconditionErrorException("Error", e);
}
}
public String getSchemaName() {
return schemaName;
}
public void setSchemaName(final String schemaName) {
this.schemaName = schemaName;
}
public String getTableName() {
return tableName;
}
public void setTableName(final String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(final String columnName) {
this.columnName = columnName;
}
public String getForeignTableName() {
return foreignTableName;
}
public void setForeignTableName(final String foreignTableName) {
this.foreignTableName = foreignTableName;
}
}
谢谢,总的来说,这可能是一个很好的解决方案。遗憾的是,我无法访问QA和生产数据库,因为它们是由指定的DBA处理的。这是一个好主意,我非常期待在Liquibase中看到它!
import liquibase.database.Database;
import liquibase.exception.CustomPreconditionErrorException;
import liquibase.exception.CustomPreconditionFailedException;
import liquibase.precondition.CustomPrecondition;
import liquibase.snapshot.SnapshotGeneratorFactory;
import liquibase.structure.core.ForeignKey;
import liquibase.structure.core.Schema;
import liquibase.structure.core.Table;
import liquibase.util.StringUtils;
/**
* {@link CustomPrecondition} implementation that checks if a column on a table
* has a foreign key constraint for some other table.
*/
public final class CheckForeignKey implements CustomPrecondition {
/**
* Schema.
*/
private String schemaName;
/**
* Table name (that has the column).
*/
private String tableName;
/**
* Column (that might have the foreign key).
*/
private String columnName;
/**
* Referenced table of the foreign key.
*/
private String foreignTableName;
@Override
public void check(final Database db)
throws CustomPreconditionFailedException,
CustomPreconditionErrorException {
try {
// The fkey we are looking for
final ForeignKey fKey = new ForeignKey();
// Schema, base table
fKey.setForeignKeyTable(new Table());
if (StringUtils.trimToNull(getTableName()) != null) {
fKey.getForeignKeyTable().setName(getTableName());
}
final Schema schema = new Schema();
schema.setName(getSchemaName());
fKey.getForeignKeyTable().setSchema(schema);
// Base column
fKey.addForeignKeyColumn(getColumnName());
// Referenced table
fKey.setPrimaryKeyTable(new Table());
if (StringUtils.trimToNull(getForeignTableName()) != null) {
fKey.getPrimaryKeyTable().setName(getForeignTableName());
}
if (!SnapshotGeneratorFactory.getInstance().has(fKey, db)) {
throw new CustomPreconditionFailedException(
String.format(
"Error fkey not found schema %s table %s column %s ftable %s",
getSchemaName(), getTableName(),
getColumnName(), getForeignTableName()));
}
} catch (final CustomPreconditionFailedException e) {
throw e;
} catch (final Exception e) {
throw new CustomPreconditionErrorException("Error", e);
}
}
public String getSchemaName() {
return schemaName;
}
public void setSchemaName(final String schemaName) {
this.schemaName = schemaName;
}
public String getTableName() {
return tableName;
}
public void setTableName(final String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(final String columnName) {
this.columnName = columnName;
}
public String getForeignTableName() {
return foreignTableName;
}
public void setForeignTableName(final String foreignTableName) {
this.foreignTableName = foreignTableName;
}
}