これが簡単なコンパレータツールに対する私の答えです
public class Comparator {
public boolean isComparatorRunning  = false;
public void compareTableColumns(List<String> tableNames) {
    if(!isComparatorRunning) {
        isComparatorRunning = true;
        try {
            for (String schTableName : tableNames) {
                Map<String, String> schemaTableMap = ComparatorUtil.getSchemaTableMap(schTableName); 
                Map<String, ColumnInfo> primaryColMap = ComparatorUtil.getColumnMetadataMap(DbConnectionRepository.getConnectionOne(), schemaTableMap);
                Map<String, ColumnInfo> secondaryColMap = ComparatorUtil.getColumnMetadataMap(DbConnectionRepository.getConnectionTwo(), schemaTableMap);
                ComparatorUtil.publishColumnInfoOutput("Comparing table : "+ schemaTableMap.get(CompConstants.TABLE_NAME));
                compareColumns(primaryColMap, secondaryColMap);
            }
        } catch (Exception e) {
            ComparatorUtil.publishColumnInfoOutput("ERROR"+e.getMessage());
        }
        isComparatorRunning = false;
    }
}
public void compareColumns(Map<String, ColumnInfo> primaryColMap, Map<String, ColumnInfo> secondaryColMap) {
    try {
        boolean isEqual = true;
        for(Map.Entry<String, ColumnInfo> entry : primaryColMap.entrySet()) {
            String columnName = entry.getKey();
            ColumnInfo primaryColInfo = entry.getValue();
            ColumnInfo secondaryColInfo = secondaryColMap.remove(columnName);
            if(secondaryColInfo == null) {
                // column is not present in Secondary Environment
                ComparatorUtil.publishColumnInfoOutput("ALTER", primaryColInfo);
                isEqual = false;
                continue;
            }
            if(!primaryColInfo.equals(secondaryColInfo)) {
                isEqual = false;
                // Column not equal in secondary env
                ComparatorUtil.publishColumnInfoOutput("MODIFY", primaryColInfo);
            }
        }
        if(!secondaryColMap.isEmpty()) {
            isEqual = false;
            for(Map.Entry<String, ColumnInfo> entry : secondaryColMap.entrySet()) {
                // column is not present in Primary Environment
                ComparatorUtil.publishColumnInfoOutput("DROP", entry.getValue());
            }
        }
        if(isEqual) {
            ComparatorUtil.publishColumnInfoOutput("--Exact Match");
        }
    } catch (Exception e) {
        ComparatorUtil.publishColumnInfoOutput("ERROR"+e.getMessage());
    }
}
public void compareTableColumnsValues(String primaryTableName, String primaryColumnNames, String primaryCondition, String primaryKeyColumn, 
        String secTableName, String secColumnNames, String secCondition, String secKeyColumn) {
    if(!isComparatorRunning) {
        isComparatorRunning = true;
        Connection conn1 = DbConnectionRepository.getConnectionOne();
        Connection conn2 = DbConnectionRepository.getConnectionTwo();
        String query1 = buildQuery(primaryTableName, primaryColumnNames, primaryCondition, primaryKeyColumn);
        String query2 = buildQuery(secTableName, secColumnNames, secCondition, secKeyColumn);
        try {
            Map<String,Map<String, Object>> query1Data = executeAndRefactorData(conn1, query1, primaryKeyColumn);
            Map<String,Map<String, Object>> query2Data = executeAndRefactorData(conn2, query2, secKeyColumn);
            for(Map.Entry<String,Map<String, Object>> entry : query1Data.entrySet()) {
                String key = entry.getKey();
                Map<String, Object> value = entry.getValue();
                Map<String, Object> secondaryValue = query2Data.remove(key);
                if(secondaryValue == null) {
                    ComparatorUtil.publishColumnValuesInfoOutput("NO SUCH VALUE AVAILABLE IN SECONDARY DB "+ value.toString());
                    continue;
                }
                compareMap(value, secondaryValue, key);
            }
            if(!query2Data.isEmpty()) {
                ComparatorUtil.publishColumnValuesInfoOutput("Extra Values in Secondary table "+ ((Map)query2Data.values()).values().toString());
            }
        } catch (Exception e) {
            ComparatorUtil.publishColumnValuesInfoOutput("ERROR"+e.getMessage());
        }
        isComparatorRunning = false;
    }
}
private void compareMap(Map<String, Object> primaryValues, Map<String, Object> secondaryValues, String columnIdentification) {
    for(Map.Entry<String, Object> entry : primaryValues.entrySet()) {
        String key = entry.getKey();
        Object value = entry.getValue();
        Object secValue = secondaryValues.get(key);
        if(value!=null && secValue!=null && !String.valueOf(value).equalsIgnoreCase(String.valueOf(secValue))) {
            ComparatorUtil.publishColumnValuesInfoOutput(columnIdentification+" : Secondary Table does not match value ("+ value +") for column ("+ key+")");
        }
        if(value==null && secValue!=null) {
            ComparatorUtil.publishColumnValuesInfoOutput(columnIdentification+" : Values not available in primary table for column "+ key);
        }
        if(value!=null && secValue==null) {
            ComparatorUtil.publishColumnValuesInfoOutput(columnIdentification+" : Values not available in Secondary table for column "+ key);
        }
    }
}
private String buildQuery(String tableName, String column, String condition, String keyCol) {
    if(!"*".equalsIgnoreCase(column)) {
        String[] keyColArr = keyCol.split(",");
        for(String key: keyColArr) {
            if(!column.contains(key.trim())) {
                column+=","+key.trim();
            }
        }
    }
    StringBuilder queryBuilder = new StringBuilder();
    queryBuilder.append("select "+column+" from "+ tableName);
    if(!ComparatorUtil.isNullorEmpty(condition)) {
        queryBuilder.append(" where 1=1 and "+condition);
    }
    return queryBuilder.toString();
}
private Map<String,Map<String, Object>> executeAndRefactorData(Connection connection, String query, String keyColumn) {
    Map<String,Map<String, Object>> result = new HashMap<String, Map<String,Object>>();
    try {
        PreparedStatement preparedStatement = connection.prepareStatement(query);
        ResultSet resultSet = preparedStatement.executeQuery();
        resultSet.setFetchSize(1000);
        if (resultSet != null && !resultSet.isClosed()) {
            while (resultSet.next()) {
                Map<String, Object> columnValueDetails = new HashMap<String, Object>();
                int columnCount = resultSet.getMetaData().getColumnCount();
                for (int i=1; i<=columnCount; i++) {
                    String columnName = String.valueOf(resultSet.getMetaData().getColumnName(i));
                    Object columnValue = resultSet.getObject(columnName);
                    columnValueDetails.put(columnName, columnValue);
                }
                String[] keys = keyColumn.split(",");
                String newKey = "";
                for(int j=0; j<keys.length; j++) {
                    newKey += String.valueOf(columnValueDetails.get(keys[j]));
                }
                result.put(newKey , columnValueDetails);
            }
        }
    } catch (SQLException e) {
        ComparatorUtil.publishColumnValuesInfoOutput("ERROR"+e.getMessage());
    }
    return result;
}
}
同じためのユーティリティツール
public class ComparatorUtil {
public static Map<String, String> getSchemaTableMap(String tableNameWithSchema) {
    if(isNullorEmpty(tableNameWithSchema)) {
        return null;
    }
    Map<String, String> result = new LinkedHashMap<>();
    int index = tableNameWithSchema.indexOf(".");
    String schemaName = tableNameWithSchema.substring(0, index);
    String tableName = tableNameWithSchema.substring(index+1);
    result.put(CompConstants.SCHEMA_NAME, schemaName);
    result.put(CompConstants.TABLE_NAME, tableName);
    return result;
}
public static Map<String, ColumnInfo> getColumnMetadataMap(Connection conn, Map<String, String> schemaTableMap) {
    try {
        String schemaName = schemaTableMap.get(CompConstants.SCHEMA_NAME);
        String tableName = schemaTableMap.get(CompConstants.TABLE_NAME);
        ResultSet resultSetConnOne = conn.getMetaData().getColumns(null, schemaName, tableName, null);
        Map<String, ColumnInfo> resultSetTwoColInfo = getColumnInfo(schemaName, tableName, resultSetConnOne);
        return resultSetTwoColInfo;
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return null;
}
/* Number Type mapping
 * 12-----VARCHAR
 * 3-----DECIMAL
 * 93-----TIMESTAMP
 * 1111-----OTHER
*/
public static Map<String, ColumnInfo> getColumnInfo(String schemaName, String tableName, ResultSet columns) {
    try {
        Map<String, ColumnInfo> tableColumnInfo = new LinkedHashMap<String, ColumnInfo>();
        while (columns.next()) {
            ColumnInfo columnInfo = new ColumnInfo();
            columnInfo.setSchemaName(schemaName);
            columnInfo.setTableName(tableName);
            columnInfo.setColumnName(columns.getString("COLUMN_NAME"));
            columnInfo.setDatatype(columns.getString("DATA_TYPE"));
            columnInfo.setColumnsize(columns.getString("COLUMN_SIZE"));
            columnInfo.setDecimaldigits(columns.getString("DECIMAL_DIGITS"));
            columnInfo.setIsNullable(columns.getString("IS_NULLABLE"));
            tableColumnInfo.put(columnInfo.getColumnName(), columnInfo);
        }
        return tableColumnInfo;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
public static boolean isNullOrEmpty(Object obj) {
    if (obj == null)
        return true;
    if (String.valueOf(obj).equalsIgnoreCase("NULL")) 
        return true;
    if (obj.toString().trim().length() == 0)
        return true;
    return false;
}
public static boolean isNullorEmpty(String str) {
    if(str == null)
        return true;
    if(str.trim().length() == 0) 
        return true;
    return false;
}
public static void publishColumnInfoOutput(String type, ColumnInfo columnInfo) {
    String str = "ALTER TABLE "+columnInfo.getSchemaName()+"."+columnInfo.getTableName();
    switch(type.toUpperCase()) {
        case "ALTER":
            if("NUMBER".equalsIgnoreCase(columnInfo.getDatatype()) || "DATE".equalsIgnoreCase(columnInfo.getDatatype())) {
                str += " ADD ("+columnInfo.getColumnName()+" "+ columnInfo.getDatatype()+");";
            } else {
                str += " ADD ("+columnInfo.getColumnName()+" "+ columnInfo.getDatatype() +"("+columnInfo.getColumnsize()+"));";
            }
            break;
        case "DROP":
            str += " DROP ("+columnInfo.getColumnName()+");";
            break;
        case "MODIFY":
            if("NUMBER".equalsIgnoreCase(columnInfo.getDatatype()) || "DATE".equalsIgnoreCase(columnInfo.getDatatype())) {
                str += " MODIFY ("+columnInfo.getColumnName()+" "+ columnInfo.getDatatype()+");";
            } else {
                str += " MODIFY ("+columnInfo.getColumnName()+" "+ columnInfo.getDatatype() +"("+columnInfo.getColumnsize()+"));";
            }
            break;
    }
    publishColumnInfoOutput(str);
}
public static Map<Integer, String> allJdbcTypeName = null;
public static Map<Integer, String> getAllJdbcTypeNames() {
    Map<Integer, String> result = new HashMap<Integer, String>();
    if(allJdbcTypeName != null)
        return allJdbcTypeName;
    try {
        for (Field field : java.sql.Types.class.getFields()) {
            result.put((Integer) field.get(null), field.getName());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return allJdbcTypeName=result;
}
public static String getStringPlaces(String[] attribs) {
    String params = "";
    for(int i=0; i<attribs.length; i++) { params += "?,"; }
    return params.substring(0, params.length()-1);
}
}
列情報クラス 
public class ColumnInfo {
private String schemaName;
private String tableName;
private String columnName;
private String datatype;
private String columnsize;
private String decimaldigits;
private String isNullable;