我想在两个CachedRowSet上执行左联接。似乎JoinRowSetImpl仅支持INNER JOIN。我可以使用什么使左加入工作?
谢谢并恭祝安康。
最佳答案
似乎以这种方式重建JoinRowSetImpl类可以解决问题。 initJOIN methot重建如下(适用于我的目的):
/**
* Internal initialization of <code>JoinRowSet</code>.
*/
private void initJOIN(CachedRowSet rowset) throws SQLException {
try {
CachedRowSetImpl cRowset = (CachedRowSetImpl) rowset;
// Create a new CachedRowSet object local to this function.
CachedRowSetImpl crsTemp = new CachedRowSetImpl();
RowSetMetaDataImpl rsmd = new RowSetMetaDataImpl();
/*
* The following 'if block' seems to be always going true. commenting this out
* for present
*
* if (!supportedJOINs[1]) { throw new
* SQLException(resBundle.handleGetObject("joinrowsetimpl.notsupported").
* toString()); }
*
*/
if (vecRowSetsInJOIN.isEmpty()) {
// implies first cRowset to be added to the Join
// simply add this as a CachedRowSet.
// Also add it to the class variable of type vector
// do not need to check "type" of Join but it should be set.
crsInternal = (CachedRowSetImpl) rowset.createCopy();
crsInternal.setMetaData((RowSetMetaDataImpl) cRowset.getMetaData());
// metadata will also set the MatchColumn.
vecRowSetsInJOIN.add(cRowset);
} else {
// At this point we are ready to add another rowset to 'this' object
// Check the size of vecJoinType and vecRowSetsInJoin
// If nothing is being set, internally call setJoinType()
// to set to JoinRowSet.INNER_JOIN.
// For two rowsets one (valid) entry should be there in vecJoinType
// For three rowsets two (valid) entries should be there in vecJoinType
// Maintain vecRowSetsInJoin = vecJoinType + 1
if ((vecRowSetsInJOIN.size() - vecJoinType.size()) == 2) {
// we are going to add next rowset and setJoinType has not been set
// recently, so set it to setJoinType() to JoinRowSet.INNER_JOIN.
// the default join type
setJoinType(JoinRowSet.INNER_JOIN);
} else if ((vecRowSetsInJOIN.size() - vecJoinType.size()) == 1) {
// do nothing setjoinType() has been set by programmer
}
// Add the table names to the class variable of type vector.
vecTableNames.add(crsInternal.getTableName());
vecTableNames.add(cRowset.getTableName());
// Now we have two rowsets crsInternal and cRowset which need
// to be INNER JOIN'ED to form a new rowset
// Compare table1.MatchColumn1.value1 == { table2.MatchColumn2.value1
// ... upto table2.MatchColumn2.valueN }
// ...
// Compare table1.MatchColumn1.valueM == { table2.MatchColumn2.value1
// ... upto table2.MatchColumn2.valueN }
//
// Assuming first rowset has M rows and second N rows.
int rowCount2 = cRowset.size();
int rowCount1 = crsInternal.size();
// total columns in the new CachedRowSet will be sum of both -1
// (common column)
int matchColumnCount = 0;
for (int i = 0; i < crsInternal.getMatchColumnIndexes().length; i++) {
if (crsInternal.getMatchColumnIndexes()[i] != -1)
++matchColumnCount;
else
break;
}
rsmd.setColumnCount(crsInternal.getMetaData().getColumnCount() + cRowset.getMetaData().getColumnCount()
- matchColumnCount);
crsTemp.setMetaData(rsmd);
crsInternal.beforeFirst();
cRowset.beforeFirst();
for (int i = 1; i <= rowCount1; i++) {
if (crsInternal.isAfterLast()) {
break;
}
if (crsInternal.next()) {
cRowset.beforeFirst();
//
int p;
int colc = 0;
// ****first with null***
crsTemp.moveToInsertRow();
boolean match = true;
// create a new rowset crsTemp with data from first rowset
for (p = 1; p <= crsInternal.getMetaData().getColumnCount(); p++) {
match = false;
for (int k = 0; k < matchColumnCount; k++) {
if (p == crsInternal.getMatchColumnIndexes()[k]) {
match = true;
break;
}
}
if (!match) {
crsTemp.updateObject(++colc, crsInternal.getObject(p));
// column type also needs to be passed.
rsmd.setColumnName(colc, crsInternal.getMetaData().getColumnName(p));
rsmd.setTableName(colc, crsInternal.getTableName());
rsmd.setColumnType(p, crsInternal.getMetaData().getColumnType(p));
rsmd.setAutoIncrement(p, crsInternal.getMetaData().isAutoIncrement(p));
rsmd.setCaseSensitive(p, crsInternal.getMetaData().isCaseSensitive(p));
rsmd.setCatalogName(p, crsInternal.getMetaData().getCatalogName(p));
rsmd.setColumnDisplaySize(p,
crsInternal.getMetaData().getColumnDisplaySize(p));
rsmd.setColumnLabel(p, crsInternal.getMetaData().getColumnLabel(p));
rsmd.setColumnType(p, crsInternal.getMetaData().getColumnType(p));
rsmd.setColumnTypeName(p, crsInternal.getMetaData().getColumnTypeName(p));
rsmd.setCurrency(p, crsInternal.getMetaData().isCurrency(p));
rsmd.setNullable(p, crsInternal.getMetaData().isNullable(p));
rsmd.setPrecision(p, crsInternal.getMetaData().getPrecision(p));
rsmd.setScale(p, crsInternal.getMetaData().getScale(p));
rsmd.setSchemaName(p, crsInternal.getMetaData().getSchemaName(p));
rsmd.setSearchable(p, crsInternal.getMetaData().isSearchable(p));
rsmd.setSigned(p, crsInternal.getMetaData().isSigned(p));
} else {
// will happen only once, for that merged column pass
// the types as OBJECT, if types not equal
crsTemp.updateObject(++colc, crsInternal.getObject(p));
rsmd.setColumnName(colc, crsInternal.getMetaData().getColumnName(p));
rsmd.setTableName(colc,
crsInternal.getTableName() + "#" + cRowset.getTableName());
rsmd.setColumnType(p, crsInternal.getMetaData().getColumnType(p));
rsmd.setAutoIncrement(p, crsInternal.getMetaData().isAutoIncrement(p));
rsmd.setCaseSensitive(p, crsInternal.getMetaData().isCaseSensitive(p));
rsmd.setCatalogName(p, crsInternal.getMetaData().getCatalogName(p));
rsmd.setColumnDisplaySize(p,
crsInternal.getMetaData().getColumnDisplaySize(p));
rsmd.setColumnLabel(p, crsInternal.getMetaData().getColumnLabel(p));
rsmd.setColumnType(p, crsInternal.getMetaData().getColumnType(p));
rsmd.setColumnTypeName(p, crsInternal.getMetaData().getColumnTypeName(p));
rsmd.setCurrency(p, crsInternal.getMetaData().isCurrency(p));
rsmd.setNullable(p, crsInternal.getMetaData().isNullable(p));
rsmd.setPrecision(p, crsInternal.getMetaData().getPrecision(p));
rsmd.setScale(p, crsInternal.getMetaData().getScale(p));
rsmd.setSchemaName(p, crsInternal.getMetaData().getSchemaName(p));
rsmd.setSearchable(p, crsInternal.getMetaData().isSearchable(p));
rsmd.setSigned(p, crsInternal.getMetaData().isSigned(p));
// don't do ++colc in the above statement
} // end if
} // end for
//*********second**************
for (int q = 1; q <= cRowset.getMetaData().getColumnCount(); q++) {
match = false;
for (int k = 0; k < matchColumnCount; k++) {
if (q == cRowset.getMatchColumnIndexes()[k]) {
match = true;
break;
}
}
if (!match) {
crsTemp.updateNull(++colc);
rsmd.setColumnName(colc, cRowset.getMetaData().getColumnName(q));
rsmd.setTableName(colc, cRowset.getTableName());
/**
* This will happen for a special case scenario. The value of 'p' will
* always be one more than the number of columns in the first rowset in the
* join. So, for a value of 'q' which is the number of columns in the second
* rowset that participates in the join. So decrement value of 'p' by 1 else
* `p+q-1` will be out of range.
**/
// if((p+q-1) > ((crsInternal.getMetaData().getColumnCount()) +
// (cRowset.getMetaData().getColumnCount()) - 1)) {
// --p;
// }
rsmd.setColumnType(p + q - 1, cRowset.getMetaData().getColumnType(q));
rsmd.setAutoIncrement(p + q - 1, cRowset.getMetaData().isAutoIncrement(q));
rsmd.setCaseSensitive(p + q - 1, cRowset.getMetaData().isCaseSensitive(q));
rsmd.setCatalogName(p + q - 1, cRowset.getMetaData().getCatalogName(q));
rsmd.setColumnDisplaySize(p + q - 1,
cRowset.getMetaData().getColumnDisplaySize(q));
rsmd.setColumnLabel(p + q - 1, cRowset.getMetaData().getColumnLabel(q));
rsmd.setColumnType(p + q - 1, cRowset.getMetaData().getColumnType(q));
rsmd.setColumnTypeName(p + q - 1,
cRowset.getMetaData().getColumnTypeName(q));
rsmd.setCurrency(p + q - 1, cRowset.getMetaData().isCurrency(q));
rsmd.setNullable(p + q - 1, cRowset.getMetaData().isNullable(q));
rsmd.setPrecision(p + q - 1, cRowset.getMetaData().getPrecision(q));
rsmd.setScale(p + q - 1, cRowset.getMetaData().getScale(q));
rsmd.setSchemaName(p + q - 1, cRowset.getMetaData().getSchemaName(q));
rsmd.setSearchable(p + q - 1, cRowset.getMetaData().isSearchable(q));
rsmd.setSigned(p + q - 1, cRowset.getMetaData().isSigned(q));
} else {
--p;
}
}
//**********second updates if foud match**************
colc = 13;
for (int j = 1; j <= rowCount2; j++) {
if (cRowset.isAfterLast()) {
break;
}
if(cRowset.next()) {
// System.out.println(cRowset.getInt(1));
match = true;
for (int k = 0; k < matchColumnCount; k++) {
if (!crsInternal.getObject(crsInternal.getMatchColumnIndexes()[k])
.equals(cRowset.getObject(cRowset.getMatchColumnIndexes()[k]))) {
match = false;
break;
}
}
if (match) {
// append the rowset crsTemp, with data from second rowset
for (int q = 1; q <= cRowset.getMetaData().getColumnCount(); q++) {
match = false;
for (int k = 0; k < matchColumnCount; k++) {
if (q == cRowset.getMatchColumnIndexes()[k]) {
match = true;
break;
}
}
if (!match) {
crsTemp.updateObject(++colc, cRowset.getObject(q));
rsmd.setColumnName(colc, cRowset.getMetaData().getColumnName(q));
rsmd.setTableName(colc, cRowset.getTableName());
/**
* This will happen for a special case scenario. The value of 'p' will
* always be one more than the number of columns in the first rowset in the
* join. So, for a value of 'q' which is the number of columns in the second
* rowset that participates in the join. So decrement value of 'p' by 1 else
* `p+q-1` will be out of range.
**/
// if((p+q-1) > ((crsInternal.getMetaData().getColumnCount()) +
// (cRowset.getMetaData().getColumnCount()) - 1)) {
// --p;
// }
rsmd.setColumnType(p + q - 1, cRowset.getMetaData().getColumnType(q));
rsmd.setAutoIncrement(p + q - 1, cRowset.getMetaData().isAutoIncrement(q));
rsmd.setCaseSensitive(p + q - 1, cRowset.getMetaData().isCaseSensitive(q));
rsmd.setCatalogName(p + q - 1, cRowset.getMetaData().getCatalogName(q));
rsmd.setColumnDisplaySize(p + q - 1,
cRowset.getMetaData().getColumnDisplaySize(q));
rsmd.setColumnLabel(p + q - 1, cRowset.getMetaData().getColumnLabel(q));
rsmd.setColumnType(p + q - 1, cRowset.getMetaData().getColumnType(q));
rsmd.setColumnTypeName(p + q - 1,
cRowset.getMetaData().getColumnTypeName(q));
rsmd.setCurrency(p + q - 1, cRowset.getMetaData().isCurrency(q));
rsmd.setNullable(p + q - 1, cRowset.getMetaData().isNullable(q));
rsmd.setPrecision(p + q - 1, cRowset.getMetaData().getPrecision(q));
rsmd.setScale(p + q - 1, cRowset.getMetaData().getScale(q));
rsmd.setSchemaName(p + q - 1, cRowset.getMetaData().getSchemaName(q));
rsmd.setSearchable(p + q - 1, cRowset.getMetaData().isSearchable(q));
rsmd.setSigned(p + q - 1, cRowset.getMetaData().isSigned(q));
} else {
--p;
}
}
cRowset.deleteRow();
break;
} else {
}
}
}
crsTemp.insertRow();
crsTemp.moveToCurrentRow();
}
} // end outer for
crsTemp.setMetaData(rsmd);
crsTemp.setOriginal();
// Now the join is done.
// Make crsInternal = crsTemp, to be ready for next merge, if at all.
int[] pCol = new int[matchColumnCount];
for (int i = 0; i < matchColumnCount; i++)
pCol[i] = crsInternal.getMatchColumnIndexes()[i];
crsInternal = (CachedRowSetImpl) crsTemp.createCopy();
// Because we add the first rowset as crsInternal to the
// merged rowset, so pCol will point to the Match column.
// until reset, am not sure we should set this or not(?)
// if this is not set next inner join won't happen
// if we explicitly do not set a set MatchColumn of
// the new crsInternal.
crsInternal.setMatchColumn(pCol);
// Add the merged rowset to the class variable of type vector.
crsInternal.setMetaData(rsmd);
vecRowSetsInJOIN.add(cRowset);
} // end if
} catch (SQLException sqle) {
// %%% Exception should not dump here:
sqle.printStackTrace();
throw new SQLException(resBundle.handleGetObject("joinrowsetimpl.initerror").toString() + sqle);
} catch (Exception e) {
e.printStackTrace();
throw new SQLException(resBundle.handleGetObject("joinrowsetimpl.genericerr").toString() + e);
}
}