Java/Oracle :查找所有相关行并更新它们
Java/Oracle : Find all Dependent Rows and Update Them
我有一个 Oracle table (COMBO_VALUES),它已被许多其他 table 引用。例如 COMBO_VALUES 中的 1 条记录可能已被 100 个不同的 table 引用。
我想找到指向 COMBO_VALUES 记录的所有相关记录(他们的 ID 和 Table 姓名),以便稍后更新它们。
我更喜欢在这个问题中使用 Java 代码,它可以利用 Oracle 元数据来收集我正在寻找的数据(我不精通 PL/SQL)。
顺便说一句,我不想改变我的 table 以拥有 "CASCADE" 选项。我想要的(至少现在)是找到依赖行 ID 和 Table 名称。
谢谢...
Oracle 不支持 当 main 中的 pk 发生变化时更新外部表中值的机制。您需要在整个参考表中手动更新值。阅读 documentation.
虽然这是一种丑陋的方式,但这是您所要求的。您可以加入 all_cons_columns 和 all_constraints 视图以获得 parent-child 基于主键-外键关系的信息。一旦你得到父 table、子 table 和引用列名,你可以稍后在子 table 上使用匹配的 MERGE父行 table.
例如,
SQL> column owner format a10
SQL> column parent_table format a15
SQL> column child_table format a15
SQL> column column_name format a15
SQL> column constraint_name format a15
SQL> column referenced_key format a15
SQL> column constraint_type format a15
SQL> set linesize 200
SQL> SELECT a.owner,
2 a.table_name parent_table,
3 b.table_name child_table,
4 a.column_name,
5 a.constraint_name,
6 b.constraint_name referenced_key,
7 b.constraint_type
8 FROM all_cons_columns a ,
9 all_constraints b
10 WHERE a.owner ='SCOTT'
11 AND a.constraint_name = b.r_constraint_name
12 AND a.table_name ='DEPT';
OWNER PARENT_TABLE CHILD_TABLE COLUMN_NAME CONSTRAINT_NAME REFERENCED_KEY CONSTRAINT_TYPE
----- ------------ ----------- ----------- --------------- --------------- ---------------
SCOTT DEPT EMP DEPTNO PK_DEPT FK_DEPTNO R
SQL>
所以,上面的查询给了我父子 table 信息以及引用的列名。根据这些信息,使用MERGE语句:
MERGE child_table c
USING parent_table p
ON (p.key = c.key)
WHEN MATCHED THEN
UPDATE SET...
请记住,您不能合并您用于加入 ON 子句的列。
我刚刚写了一个 class,它完全符合我的要求:
- 尝试删除可能已被其他记录引用的记录
- 查找所有子项并将其引用更改为新 ID
- 最后删除记录
这是我想出的代码(抱歉,它可能不够好):
public class RowFinder {
boolean autoCommit;
public RowFinder(boolean autoCommit) {
this.autoCommit = autoCommit;
}
public static void main(String[] args) {
RowFinder rowFinder = new RowFinder(false);
rowFinder.findRows("YOUR_TABLE_NAME", "PRIMARY_KEY_FIELD_NAME", "OLD_ID", "NEW_ID_FOR_CHILDREN");
}
public void findRows(String tableName, String columnName, String oldId, String newId) {
Connection connection = null;
java.sql.Statement statement = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
connection = DriverManager.getConnection("jdbc:oracle:thin@DB_IP_ADDRESS:1521:SID", "USER", "PASS");
connection.setAutoCommit(autoCommit);
statement = connection.createStatement();
System.out.println(String.format("\nTrying to Delete %s with Old ID: '%s' and Update Children with New ID: '%s'", tableName, oldId, newId));
boolean flag = true;
long counter = 1;
while (flag) {
try {
String deleteQuery = String.format("delete from %s where %s = %s", tableName, columnName, oldId);
statement.executeUpdate(deleteQuery);
flag = false;
} catch (SQLException e) {
String errorMessage = e.getMessage();
//TRYING TO FIND THE CONSTRAINT NAME FROM ERROR - YOU CAN CHANGE IT ACCORDING TO YOUR PROJECT SETTINGS
Pattern pattern = Pattern.compile("\(PROJECT_NAME\.(.*)\)");
Matcher matcher = pattern.matcher(errorMessage);
String referenceName;
if (matcher.find()) {
referenceName = matcher.group(1);
String constraintTableQuery = String.format("SELECT ucc.table_name,ucc.column_name FROM user_cons_columns ucc WHERE ucc.constraint_name = '%s'", referenceName);
try {
ResultSet resultSet = statement.executeQuery(constraintTableQuery);
resultSet.next();
String constraintTableName = resultSet.getString(1);
String constraintColumnName = resultSet.getString(2);
String updateQuery = String.format("UPDATE %s SET %s = '%s' WHERE %s = '%s'", constraintTableName, constraintColumnName, newId, constraintColumnName, oldId);
statement.executeUpdate(updateQuery);
System.out.println(String.format("%s. Updated Child Located at : %s => %s",counter++,constraintTableName,constraintColumnName));
} catch (SQLException e1) {
e1.printStackTrace();
}
} else {
System.out.println("Matcher didn't find anything... Exiting...");
if (autoCommit)
connection.commit();
else
connection.rollback();
statement.close();
connection.close();
System.exit(0);
}
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (autoCommit){
System.out.println("Deleted the Record and Changed its Children.");
connection.commit();
}
else{
System.out.println("Rolling Back Changes...");
connection.rollback();
}
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
我有一个 Oracle table (COMBO_VALUES),它已被许多其他 table 引用。例如 COMBO_VALUES 中的 1 条记录可能已被 100 个不同的 table 引用。
我想找到指向 COMBO_VALUES 记录的所有相关记录(他们的 ID 和 Table 姓名),以便稍后更新它们。
我更喜欢在这个问题中使用 Java 代码,它可以利用 Oracle 元数据来收集我正在寻找的数据(我不精通 PL/SQL)。
顺便说一句,我不想改变我的 table 以拥有 "CASCADE" 选项。我想要的(至少现在)是找到依赖行 ID 和 Table 名称。
谢谢...
Oracle 不支持 当 main 中的 pk 发生变化时更新外部表中值的机制。您需要在整个参考表中手动更新值。阅读 documentation.
虽然这是一种丑陋的方式,但这是您所要求的。您可以加入 all_cons_columns 和 all_constraints 视图以获得 parent-child 基于主键-外键关系的信息。一旦你得到父 table、子 table 和引用列名,你可以稍后在子 table 上使用匹配的 MERGE父行 table.
例如,
SQL> column owner format a10
SQL> column parent_table format a15
SQL> column child_table format a15
SQL> column column_name format a15
SQL> column constraint_name format a15
SQL> column referenced_key format a15
SQL> column constraint_type format a15
SQL> set linesize 200
SQL> SELECT a.owner,
2 a.table_name parent_table,
3 b.table_name child_table,
4 a.column_name,
5 a.constraint_name,
6 b.constraint_name referenced_key,
7 b.constraint_type
8 FROM all_cons_columns a ,
9 all_constraints b
10 WHERE a.owner ='SCOTT'
11 AND a.constraint_name = b.r_constraint_name
12 AND a.table_name ='DEPT';
OWNER PARENT_TABLE CHILD_TABLE COLUMN_NAME CONSTRAINT_NAME REFERENCED_KEY CONSTRAINT_TYPE
----- ------------ ----------- ----------- --------------- --------------- ---------------
SCOTT DEPT EMP DEPTNO PK_DEPT FK_DEPTNO R
SQL>
所以,上面的查询给了我父子 table 信息以及引用的列名。根据这些信息,使用MERGE语句:
MERGE child_table c
USING parent_table p
ON (p.key = c.key)
WHEN MATCHED THEN
UPDATE SET...
请记住,您不能合并您用于加入 ON 子句的列。
我刚刚写了一个 class,它完全符合我的要求:
- 尝试删除可能已被其他记录引用的记录
- 查找所有子项并将其引用更改为新 ID
- 最后删除记录
这是我想出的代码(抱歉,它可能不够好):
public class RowFinder {
boolean autoCommit;
public RowFinder(boolean autoCommit) {
this.autoCommit = autoCommit;
}
public static void main(String[] args) {
RowFinder rowFinder = new RowFinder(false);
rowFinder.findRows("YOUR_TABLE_NAME", "PRIMARY_KEY_FIELD_NAME", "OLD_ID", "NEW_ID_FOR_CHILDREN");
}
public void findRows(String tableName, String columnName, String oldId, String newId) {
Connection connection = null;
java.sql.Statement statement = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
connection = DriverManager.getConnection("jdbc:oracle:thin@DB_IP_ADDRESS:1521:SID", "USER", "PASS");
connection.setAutoCommit(autoCommit);
statement = connection.createStatement();
System.out.println(String.format("\nTrying to Delete %s with Old ID: '%s' and Update Children with New ID: '%s'", tableName, oldId, newId));
boolean flag = true;
long counter = 1;
while (flag) {
try {
String deleteQuery = String.format("delete from %s where %s = %s", tableName, columnName, oldId);
statement.executeUpdate(deleteQuery);
flag = false;
} catch (SQLException e) {
String errorMessage = e.getMessage();
//TRYING TO FIND THE CONSTRAINT NAME FROM ERROR - YOU CAN CHANGE IT ACCORDING TO YOUR PROJECT SETTINGS
Pattern pattern = Pattern.compile("\(PROJECT_NAME\.(.*)\)");
Matcher matcher = pattern.matcher(errorMessage);
String referenceName;
if (matcher.find()) {
referenceName = matcher.group(1);
String constraintTableQuery = String.format("SELECT ucc.table_name,ucc.column_name FROM user_cons_columns ucc WHERE ucc.constraint_name = '%s'", referenceName);
try {
ResultSet resultSet = statement.executeQuery(constraintTableQuery);
resultSet.next();
String constraintTableName = resultSet.getString(1);
String constraintColumnName = resultSet.getString(2);
String updateQuery = String.format("UPDATE %s SET %s = '%s' WHERE %s = '%s'", constraintTableName, constraintColumnName, newId, constraintColumnName, oldId);
statement.executeUpdate(updateQuery);
System.out.println(String.format("%s. Updated Child Located at : %s => %s",counter++,constraintTableName,constraintColumnName));
} catch (SQLException e1) {
e1.printStackTrace();
}
} else {
System.out.println("Matcher didn't find anything... Exiting...");
if (autoCommit)
connection.commit();
else
connection.rollback();
statement.close();
connection.close();
System.exit(0);
}
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (autoCommit){
System.out.println("Deleted the Record and Changed its Children.");
connection.commit();
}
else{
System.out.println("Rolling Back Changes...");
connection.rollback();
}
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}