I have a solution that is functional but not optimal:
- It requires to load all rows into in-memory data structures (each ResultSet is loaded into list, each item is map of column name-value)
- loop on source rows' list and for every item in that list - search that it does not exist in target list (meaning o(n^2) processing)
I used Apache DbUtils to easily convert ResultSet to List.
import java.sql.*;
import java.util.*;
import java.util.stream.*;
import org.apache.commons.dbutils.handlers.MapListHandler;
try (Connection conn = DriverManager.getConnection(url, user, password)) {
// load source table
Statement st = conn.createStatement();
ResultSet sourceRs = st.executeQuery("SELECT * FROM source");
List<Map<String, Object>> sourceRows = new MapListHandler().handle(sourceRs);
sourceRs.close();
st.close();
// load target table
st = conn.createStatement();
ResultSet targetRs = st.executeQuery("SELECT * FROM target");
List<Map<String, Object>> targetRows = new MapListHandler().handle(targetRs);
targetRs.close();
st.close();
// for every row in source, look for no match in target
List<Map<String, Object>> diffRows =
sourceRows.stream()
.filter(sourceRow -> rowExistsInTable(sourceRow, targetRows) == false)
.collect(Collectors.toList());
diffRows.stream().forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
}
EDIT:
you will notice that the filtering of sourceRows
is now done according to result of method rowExistsInTable()
. I added methods to search row in table and check rows' equality without relying on java 8 lambda syntax (also added as much documentation as I could :))
/**
* checks if {@code searchRow} exists in {@code table}
* existence is determined according to {@code areRowsEqual} method
* @param searchRow {@code Map<String, Object>} where keys are column names and values are column vales
* @param table {@code List} of {@code Map<String, Object>} rows
* @return {@code true} if {@code searchRow} was found in {@code table}
*/
public static boolean rowExistsInTable(Map<String, Object> searchRow, List<Map<String, Object>> table)
{
for (Map<String, Object> tableRow : table) {
if (areRowsEqual(tableRow, searchRow)) return true;
}
return false;
}
/**
* checks if all of row1 columns are found with same values in row2
* note: does not check if there is column in row2 that does not exist in row1
* @param row1
* @param row2
* @return {@code true} if {@code row1} is equal to {@code row2}
*/
public static boolean areRowsEqual(Map<String, Object> row1, Map<String, Object> row2)
{
// loop on row1 columns
for (Map.Entry<String, Object> row1Column : row1.entrySet()) {
String row1ColumnName = row1Column.getKey();
Object row1ColumnValue = row1Column.getValue();
// search row1 column in row2
if (row2.containsKey(row1ColumnName) &&
row2.get(row1ColumnName) != null &&
row2.get(row1ColumnName).equals(row1ColumnValue)) {
// row1 column was found in row2, nothing to do
} else {
// row1 column was not found in row2
return false;
}
}
return true; // all row 1 columns found in row 2
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…