# Filtern innerhalb eines Resultset



## FenchelT (30. Jul 2007)

Hallo zusammen,

in VB6 ist es z.B. moeglich, innerhalb eines Resultsets einen Filter zu setzen.
Geht das in Java auch?

Hintergrund der Frage:
Ich moechte gerne ein Eingabesensitives-JTextField erstellen.
Meine Vorstellung: 
zu Beginn wird die Datenmenge aus der Tabelle geladen (ca. 500 Datensaetze) und in einer JTable angezeigt.
Nun soll der Benutzer in ein Textfeld einen Suchbegriff eingeben und mit jedem Buchstaben den er eingibt, soll sich die Datenmege reduzieren/anpassen.
Nun moechte ich ungerne fuer jeden Buchstaben den der User eingibt eine neue Anfrage an die DB schicken, sondern lieber innerhalb des Resultsets filtern.

Ist das moeglich?


Vielen Dank und viele Gruesse
FenchelT


----------



## SlaterB (30. Jul 2007)

ich empfehle dir ganz dringend, das Resultset 100 ms nach dem Laden wieder zu schließen, 
und nicht über Sekunden/ Minuten offenzuhalten,
das mag in deinem Fall nicht direkt stören, da die DB sonst nix zu tun hat, ist aber ein allgemeines Paradigma

die Informationen kannst du genausogut in ein eigenen einfachen Datencontainern vorhalten und darüber nach belieben filtern,
müsstest dann natürlich alles selber machen (vielleicht sowieso, falls es das im ResultSet nicht gibt)


----------



## FenchelT (30. Jul 2007)

Hallo Slater,

ersteinmal Danke fuer DEine so schnelle Antwort.
Natuerlich habe ich mir auch Gedanken darueber gemacht, das Ganze in einem anderen Datencontainer aufzubewahren und darauf zu filtern.
Dann muesste ich aber saemtlichen ResultSet-Faehigkeiten nachprogrammieren und das wuerde ich ja gerne vermeiden.




> ich empfehle dir ganz dringend, das Resultset 100 ms nach dem Laden wieder zu schließen,
> und nicht über Sekunden/ Minuten offenzuhalten,
> das mag in deinem Fall nicht direkt stören, da die DB sonst nix zu tun hat, ist aber ein allgemeines Paradigma



Hmm, dies wiederum ist eine Aussage die ich nicht nachvollziehen kann.
100ms weil es alle so machen, ist nicht wirklich ein Grund.

Warum nicht 175 oder 224ms, oder 90 oder 78? Koenntest Du mir evtl die 100ms fachlich begruenden?

Nochmals Danke fuer DEine Hilfe.

FenchelT


----------



## SlaterB (30. Jul 2007)

...
das ist nur eine Zahl, lesen und fertig, egal wie lange es dauert,
jedenfalls nicht in eine JTable als Exemplarvariable stecken und auf idle setzen (bis der User das Programm beendet)

ich weiß nicht was du alles an toller Funktionalität in dem ResulSet findest,
aber ein Unabhängigkeit der Anzeige von der Logik oder gar DB-Schicht der Anwendung ist noch so eine Weisheit die ich dir mitgebe,
in kleinen Anwendungen vielleicht weniger wichtig, das mag sein


----------



## FenchelT (30. Jul 2007)

SlaterB hat gesagt.:
			
		

> ...
> das ist nur eine Zahl, lesen und fertig, egal wie lange es dauert,
> jedenfalls nicht in eine JTable als Exemplarvariable stecken und auf idle setzen (bis der User das Programm beendet)
> 
> ...




Hallo nochmal,

alles klar, ich dachte schon die 100ms hat irgendeine besondere Java-Relevanz.  :wink: 

Ich beschaeftige mich im Moment mit CachedRowSets um auch eine gewisse Unabhaengigkeit realisieren zu koennen.

Danke nochmals fuer Deine Tips


----------



## HoaX (30. Jul 2007)

für sowas verwende ich immer glazedlists (http://publicobject.com/glazedlists/)


----------



## FenchelT (30. Jul 2007)

HoaX hat gesagt.:
			
		

> für sowas verwende ich immer glazedlists (http://publicobject.com/glazedlists/)



Kracher  :toll: 

Vielen Dank   

Gruesse
FenchelT


----------



## FenchelT (18. Sep 2007)

Hallo zusammen,

wuerde gerne diesen Thread noch einmal oeffnen, da ich eine Umsetzung zu meiner einstigen Fragestellung nun doch selbst in die Hand genommen habe.

Nochmal zusammengefasst moechte ich eine "sensitive" Suche anbieten.
Soll heissen, ich habe eine Combobox die mit den Spaltennamen aus dem Resultset gefuellt wird.
Dann habe ich ein JTextField mit einem KeyListener, welcher nach einem eingegebenen Zeichen ein FilteredRowSet bemueht. Das FilteredRowSet aktualisiert das TableModel wonach dann die uebrig gebliebenen DS angezeigt in der JTable angezeigt werden.

Zum Schluss habe ich dann eine Fehlermeldung und wuerde gerne Wissen was ich dagegen tun kann, zumal die Daten trotzdem richtig gefiltert angezeigt werden.


Die Control-Klasse


```
public class SensitiveSearchCtrl 
implements KeyListener
{
	private SensitiveSearch searchPanel;
	private DaapTableModel model;
	private RecordSets rec; 
	private Connection cn;
	private String sql;
	private FilteredRowSet frs;
	private ResultSetMetaData meta;

	
	public SensitiveSearchCtrl(Connection con)
	{
		this.cn = con;
		this.rec = new RecordSets(this.cn);
		this.searchPanel = new SensitiveSearch();
		init();
	}
	
	private void init()
	{
		this.sql = "SELECT ID, Name, Plz,  Ort FROM tabelle WHERE loeschkz ='A'";
		this.frs = this.rec.getFilteredRowSet(this.sql);
		this.searchPanel.txtSearchText.addKeyListener(this);
		
		try
		{
			this.model = new DaapTableModel(this.frs);
			this.meta = this.frs.getMetaData();
			
			for (int i = 1; i <= this.meta.getColumnCount(); i++)
			{
				this.searchPanel.cboSearchField.addItem(this.meta.getColumnName(i));

			}
			
			this.searchPanel.table.setModel(this.model);
		}
		catch(SQLException ex)
		{
			System.out.println("Debug: Fehler");
			System.out.println(ex.getErrorCode());
		}
		
		//this.searchPanel.table.setModel(this.model);
	}
	
	
	private void changeTableData(String s, String c)
	{
		String searchString = s;
		String searchColumnName = c;
		
		
		MyFilter filter = new MyFilter(searchString, searchColumnName);
		
		
		try
		{			
			this.frs.beforeFirst();
			this.frs.setFilter(filter);
			this.frs.next();
			
			while(!this.frs.isLast())
			{
				this.frs.next();
				this.model.fireTableDataChanged();
			
			}
			//this.model.fireTableDataChanged();
			
		}
		
		catch (SQLException e) 
		{
			System.err.println("changeTableData");
			System.err.println("-----------------------------");
			while (e != null) 
			{
			    System.err.println(e.toString());
			    System.err.println("SQL-State: " + e.getSQLState());
			    System.err.println("ErrorCode: " + e.getErrorCode());
			   
			    e = e.getNextException();
 		  	}
 		  	
		}
	}
	
	
	private void doFiltering()
	{
		String searchString = this.searchPanel.txtSearchText.getText();
		String searchColumn = (String) this.searchPanel.cboSearchField.getSelectedItem();
		//System.out.println(searchColumn);
		changeTableData(searchString, searchColumn);
	}
	
	
	public SensitiveSearch getSearchPanel() {
		return searchPanel;
	}

	public void setSearchPanel(SensitiveSearch searchPanel) {
		this.searchPanel = searchPanel;
	}
	
	public void keyPressed(KeyEvent k) {
		// TODO Auto-generated method stub
		
	}

	public void keyReleased(KeyEvent k) 
	{	
		// System.out.println("Debug: Es wurde die Taste " + k.getKeyChar() + " gedrückt");
		doFiltering();
		
	}

	public void keyTyped(KeyEvent k ) {
		// TODO Auto-generated method stub
		
	}
}
```


Dann haette ich noch mein Table Model anzubieten:


```
public class DaapTableModel extends AbstractTableModel 
{
	private ResultSet rst;
	private ResultSetMetaData meta;
	
	public DaapTableModel(ResultSet resultSet) throws SQLException
	{
		this.rst = resultSet;
		
		try
		{
			this.meta = this.rst.getMetaData();
		}
		catch(SQLException ex)
		{
			System.out.println("Konstruktor: \n" +ex.getMessage());
		}
	}
	
	
	public int getRowCount()
	{
		try
		{
			this.rst.last();
			return this.rst.getRow();
		}
		catch(Exception ex)
		{
			System.out.println("getRowCount: \n" +ex.getMessage());
			return -1;
		}
	}
	
	public int getColumnCount()
	{
		try
		{
			return this.meta.getColumnCount();
		}
		catch(SQLException ex)
		{
			System.out.println("getColumnCount: \n" +ex.getMessage());
			return -1;
		}
		
	}
	
	
	public Object getValueAt(int row, int column)
	{
		try
		{
			this.rst.absolute(row+1);
			return this.rst.getObject(column+1);
		}
		catch(SQLException ex)
		{
			
			System.out.println("getValueAt: \n" +ex.getMessage());
			while (ex != null) 
			{
			    System.err.println(ex.toString());
			    System.err.println("SQL-State: " + ex.getSQLState());
			    System.err.println("ErrorCode: " + ex.getErrorCode());
			   
			    ex = ex.getNextException();
 		  	}
			return null;
		}
	
	}
	
	
	public String getColumnName(int column)
	{
		try
		{	
			return this.meta.getColumnName(column+1);
		}
		catch(SQLException ex)
		{
			System.out.println("getColumnName: \n" + ex.getMessage());
			return "";
		}
	}
}
```



Die Filterklasse:


```
public class MyFilter implements Predicate
{
	private String searchString = null;
	private String columnName = null;

	
	public MyFilter(String searchString, String columnName)
	{
		this.searchString = searchString;
		this.columnName = columnName;
	}
	
	public MyFilter()
	{
		
	}

	
	
	public boolean evaluate(Object arg0, int arg1) throws SQLException {
		System.out.println("Oho");
		
		
		return false;
	}


	public boolean evaluate(Object arg0, String arg1) throws SQLException {
		System.out.println("Aha");
		return false;
	}




	public boolean evaluate(RowSet rs) //throws javax.sql.rowset.Predicate.evaluate.SQLException
	{
		
		if (rs == null) 
		{
			System.out.println("Debug1");
			return false;
		}
		
		
		FilteredRowSet frs = (FilteredRowSet) rs;
		boolean evaluation = false;
		
		
		try 
		{
			//System.out.println("Debug2");
			String columnValue = frs.getString(this.columnName);
  
			if (columnValue != null)
			{
				
				if (columnValue.contains(this.searchString)) 
				{
					evaluation = true;
				}
			}
			
			
		
		} 
		catch (SQLException e) 
		{	
			System.err.println("Evaluate");
			System.err.println("--------");
			
			while (e != null) 
			{
				    System.err.println(e.toString());
				    System.err.println("SQL-State: " + e.getSQLState());
				    System.err.println("ErrorCode: " + e.getErrorCode());
				    e = e.getNextException();
			}
				  
			
			return false;
		}
		
		
		return evaluation;
	}

}
```




Und die Fehlermeldung:


```
getValueAt: 
Ungültige Cursorposition
java.sql.SQLException: Ungültige Cursorposition
SQL-State: null
ErrorCode: 0
java.sql.SQLException: Ungültige Cursorposition
SQL-State: null
ErrorCode: 0
java.sql.SQLException: Ungültige Cursorposition
SQL-State: null
ErrorCode: 0
getValueAt: 
Ungültige Cursorposition
java.sql.SQLException: Ungültige Cursorposition
SQL-State: null
ErrorCode: 0
```

Die Fehlermeldung wird von meiner TableModel Klasse geschmissen und zwar ab der Eingabe des 4. Zeichens und zwar in der Methode getValueAt und ich stehe im Moment maechtig auf dem Schlauch.   

Ich hoffe, ihr koennt mir weiterhelfen?!


Gruesse
FenchelT


----------



## Beni (21. Sep 2007)

Schön, dass du SlaterB's Einwände ignorierst... :wink:

Hat es überhaupt noch ein Datenset das durch den Filter kommt? 
Man sollte dabei auch beachten, dass "last" nicht unbedingt eine existierende Zeile anspringt (steht jedenfalls in der API :wink: ), wahrscheinlich gibt "getRowCount" einen falschen Wert zurück.


----------



## FenchelT (21. Sep 2007)

Beni hat gesagt.:
			
		

> Schön, dass du SlaterB's Einwände ignorierst... :wink:



Wie meinen ?   
Er sprach davon, dass ich kein ResultSet offen halten sollte, das in direktem Kontakt mit der DB steht.
Das tue ich ja auch nicht, ich benutze ja ein FilteredRowSet, welches ja vom Prinzip her genauso Standalone wie ein CachedRowSet arbeitet.
Oder meintest Du jetzt was ganz anderes, was ich evtl voellig ueberlesen habe?  ???:L 


```
Hat es überhaupt noch ein Datenset das durch den Filter kommt?
```

Das ist ja das urige,  die Daten werden ja fein gefiltert wie gewuenscht in der Tabelle dargestellt. Allerdings kommt der o.g Fehler  :autsch: 



```
Man sollte dabei auch beachten, dass "last" nicht unbedingt eine existierende Zeile anspringt (steht jedenfalls in der API icon_wink.gif ), wahrscheinlich gibt "getRowCount" einen falschen Wert zurück
```

Das werde ich mir entweder heute abend noch oder spaet. morgen ansehen und testen.


Danke schonmal fuer Deine Antwort   :wink:


----------



## Beni (21. Sep 2007)

FenchelT hat gesagt.:
			
		

> Wie meinen ?
> Er sprach davon, dass ich kein ResultSet offen halten sollte, das in direktem Kontakt mit der DB steht.
> Das tue ich ja auch nicht, ich benutze ja ein FilteredRowSet, welches ja vom Prinzip her genauso Standalone wie ein CachedRowSet arbeitet.
> Oder meintest Du jetzt was ganz anderes, was ich evtl voellig ueberlesen habe?  ???:L



Oje, das wusste ich nicht


----------



## FenchelT (22. Sep 2007)

Beni hat gesagt.:
			
		

> Oje, das wusste ich nicht




Ist ja nicht weiter schlimm, so haste auch noch was gelernt *feix*   :bae: 
Aber ich werde wie gesagt trotzdem nachher Deinen Vorschlag testen. Bin nur gerade etwas im Stress, fahre morgen in Urlaub


----------



## FenchelT (7. Okt 2007)

Hallo zusammen,

so, bin nun aus dem Urlaub zurueck und habe mich wieder meinem Problem gewidmet.
Folgendes ist mir aufgefallen:

Wenn ich am Anfang die Tabelle befuelle und anzeige, dann ist jede Zeile befuellt; es gibt keine Leerzeilen.
Mit jedem weiteren eingegebenen Wert wird die Ergebnismenge zwar richtig reduziert, es werden aber weiterhin alle Zeilen der Tabelle angezeigt. (ohne Werte, dafuer aber leer)
Sobald die Anzahl der Leerzeilen den sichtbaren Bereich erreicht, tritt der Fehler auf.

Gibt es eine Moeglichkeit, die Anzahl der dargestellten Zeilen der Tabelle an die tatsaechlich benoetigte Anzahl anzupassen?


Vielen Dank und viele Gruesse


----------

