# Hibernate: min und max(pkid) ermitteln



## NTB (9. Aug 2007)

Hi,

ich nutze Hibernate und habe damit bisher recht wenig Erfahrung.

Ich habe "Item"-Objekte die in der gleichnamigen Tabelle gehalten werden. Jedes Item hat eine ID und ein Attribut.
Die IDs gehen von m bis n, d.h. sie fangen nicht bei 0 oder 1 an und müssen nicht ununterbrochen fortlaufend sein. Das ist so gegeben, und ich kann es nicht ändern.

Nun möchte ich über jedes einzelne Objekt in der Tabelle Berechnungen anstellen.

Da ich eine große Anzahl von Objekten habe, kann ich nicht alle auf einmal laden, sondern möchte jedes einzeln laden.

Mein Plan ist nun, dass ich mir die niedrigste und höchste ID schnappe und alles dazwischen einzeln mit "session.get(Item.class, id)" durchgehe. Wenn eine ID nicht vorhanden ist, kommt "null" zurück, und ich nehme die nächste ID.

Was mir aber nicht klar ist: Wie bekomme ich mit Hibernate die niedrigste und höchste ID heraus? Also quasi "select min(pkid), max(pkid) from items". 

Nimmt man dafür HQL? Oder gibt es da etwas schlaueres, dass auch die Mappings aus den XML verwendet?


----------



## Guest (9. Aug 2007)

Siehe
http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#setFirstResult(int)
http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#setMaxResults(int)


----------



## NTB (10. Aug 2007)

Danke für die Antwort. Leider hilft sie mir nicht weiter, weil ich genau das Gegenteil dessen suche: Ich möchte ja First und Max herausfinden.

Hat noch jemand eine Idee?


----------



## SlaterB (10. Aug 2007)

wie könnten da die Mappings helfen?

select min(pkid), max(pkid) from items
funktioniert in Hibernate und dürfte SQL-Standard, also auch in deiner DB vorhanden sein

um bei nicht fortlaufender Nummer nicht ständig unbenutzte Ids anzufragen,
könntest du aber später > letzteId maxResults 1 verwenden
(testen, ob dann nicht langsamer als viele Einzelanfragen)


----------



## NTB (10. Aug 2007)

Das mit den Mappings kam so ein bißchen aus meinem Hirn gesprudelt und ist dadurch etwas kurz geraten 
Wenn ich das Statement so verwende, habe ich den Tabellennamen "Items" ja hart verdrahtet... wenn nun ein schlauer Fuchs irgendwann auf die Idee kommt, andere Tabellennamen zu verwenden und diese in den Mappings anpasst, dann siehts hier halt schlecht aus. Daher stellte sich mir die Frage, ob es da etwas schlaues gibt, was eben über die Mappings die max und min ID heruasfindet. Das ist mir aber momentan nicht so sehr wichtig.

Wenn Dir da auch nichts schlaueres einfällt, nehme ich tatsälich das native SQL Statement. Das ist ja auch SQL92 Standard. Momentan kommt Postgres zum Einsatz und das kann es auf jeden Fall 

Bei Deinem Einwand fällt mir ein, dass ich mir auch einfach per nativem SQL Statement nur die IDs holen kann. Dann erübrigt sich der ganze Kram mit unbenutzten, min und max IDs.


----------



## SlaterB (10. Aug 2007)

> Wenn Dir da auch nichts schlaueres einfällt, nehme ich tatsälich das native SQL Statement. 

>  habe ich den Tabellennamen "Items" ja hart verdrahtet

wie gesagt: min/ max funktioniert in H Q L (H Q L, das ist das, was nicht SQL ist  )


----------



## NTB (10. Aug 2007)

Ach so war das gemeint mit dem SQL-Standard gemeint. Ok 
Danke Dir!


----------



## SlaterB (10. Aug 2007)

sum und average gehen auch,
gemeinerweise aber median() nicht (da ärgere ich mich mit rum)


----------



## semi (11. Aug 2007)

NTB hat gesagt.:
			
		

> Danke für die Antwort. Leider hilft sie mir nicht weiter, weil ich genau das Gegenteil dessen suche: Ich möchte ja First und Max herausfinden.
> 
> Hat noch jemand eine Idee?


Ich meinte, verwende die zwei Methoden, um durch die Tabelle zu iterieren. Das Problem ist ja, dass es zu viele 
Daten sind, um sie auf einmal zu laden. Right? Dann lade jeweils SUBLIST_SIZE Einträge, bearbeite sie und setze 
mit dem nächsten Abschnitt fort.

z.B. wie folgt
	
	
	
	





```
Query query = ...
query.setMaxResults(SUBLIST_SIZE);
List<Whatever> list;
for(int offset=0; offset%SUBLIST_SIZE==0; offset+=list.size())
{
   query.setFirstResult(offset);
   if(list != null)
   {
      list.clear(); // Liste leeren, damit zum Zeitpunkt der Abfrage keine zwei Listen im Speicher sind
      list = null;
   }
   list = query.getResultList();

   processSublist(Collections.unmodifiableList(list)); // hier kannst du die Teilliste durchgehen
}
```
Man könnte daraus auch einen Iterator/Iterable mache, um es wie folgt zu verwenden.
	
	
	
	





```
Query query = ...
query.setParameter(...);

// Alle Datensätze durchgehen und dabei jeweils nur SUBLIST_SIZE-Datensätze laden.
for(Whatever a : new QueryIterator<Whatever>(query, SUBLIST_SIZE))
{
   ...
}

final class QueryIterator<T> implements Iterator<T>, Iterable<T>
{
   ...
}
```
Den QueryIterator kannst du aus der Schleife im ersten Code-Abschnitt machen.
Das wäre dann überall wiederverwendbar.


----------

