Ich würde gerne den Grund für diese Unterlassung kennen.
Slamice
Mein Verständnis der Frage war, dass Sie die Größe des ResultSet IN BYTES ermitteln möchten, nicht die Anzahl der Tupel ...
DejanLekic
Es ist sehr ärgerlich, vor Prozessdaten nicht die richtige Dimension zu haben. Wenn Sie sie jedoch in einem Array speichern müssen, können Sie eine Datenstruktur wie List verwenden und sie dann mit der toArray () -Methode in ein Array konvertieren.
AndreaTaroni86
Antworten:
270
SELECT COUNT(*) FROM ...Führen Sie stattdessen eine Abfrage durch.
ODER
int size =0;if(rs !=null){
rs.last();// moves cursor to the last row
size = rs.getRow();// get row id }
In beiden Fällen müssen Sie nicht die gesamten Daten durchlaufen.
last () und getRow () sind keine statischen Methoden in der ResultSet-Klasse.
JeeBee
70
Der Kürze halber beziehe ich mich immer auf Methoden auf diese Weise, wenn ich anderen darüber schreibe, unabhängig davon, ob sie statisch sind oder nicht. Das tatsächliche Erstellen einer Instanz des Objekts und das Aufrufen der Methode ist impliziert.
Laz
51
Ich schreibe SomeClass.staticMethod () und SomeClass # instanceMethod () für weniger Verwirrung.
Jake
9
Wie ruft man den Wert ab, der bei der Ausführung von a zurückgegeben wird select count?
Naftuli Kay
16
ResultSet#last()funktioniert nicht bei allen Arten von ResultSetObjekten, Sie müssen sicherstellen, dass Sie eines verwenden, das entweder ResultSet.TYPE_SCROLL_INSENSITIVEoderResultSet.TYPE_SCROLL_SENSITIVE
Marius Ion
91
ResultSet rs = ps.executeQuery();int rowcount =0;if(rs.last()){
rowcount = rs.getRow();
rs.beforeFirst();// not rs.first() because the rs.next() below will move on, missing the first element}while(rs.next()){// do your standard per row stuff}
Wäre im Codeblock if (rs.last ()) nicht die richtige Methode rs.beforeFirst () anstelle von rs.first ()? Auf diese Weise überspringen Sie nicht den ersten Datensatz in Ihrer Ergebnismenge für die Verarbeitung in der while-Schleife.
Karlgrz
Vergessen Sie nicht, den Cursor außerhalb des if-Blocks auf beforeFirst zurückzusetzen?
Gobliins
Wie ResultSet-Dokumente sagen, getRow()funktioniert es für TYPE_FORWARD_ONLYResultSets und beforeFirst()wirft Fehler für diese aus. Ist diese Antwort dann nicht fehlerhaft?
CodePro_NotYet
5
Dies funktioniert nur, wenn die Anweisung mit der Option ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
scrollunempfindlich
19
Nun, wenn Sie einen ResultSetTyp haben ResultSet.TYPE_FORWARD_ONLY, möchten Sie ihn so lassen (und nicht zu einem ResultSet.TYPE_SCROLL_INSENSITIVEoder wechseln, ResultSet.TYPE_SCROLL_INSENSITIVEum ihn verwenden zu können .last()).
Ich schlage einen sehr schönen und effizienten Hack vor, bei dem Sie oben eine erste falsche / falsche Zeile hinzufügen, die die Anzahl der Zeilen enthält.
Beispiel
Angenommen, Ihre Anfrage lautet wie folgt
select MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR
from MYTABLE
where...blahblah...
und Ihre Ausgabe sieht aus wie
true65537"Hey"-32768"The quick brown fox"false123456"Sup"300"The lazy dog"false-123123"Yo"0"Go ahead and jump"false3"EVH"456"Might as well jump"...[1000 total rows]
Refaktorieren Sie Ihren Code einfach wie folgt:
Statement s=myConnection.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);String from_where="FROM myTable WHERE ...blahblah... ";//h4xResultSet rs=s.executeQuery("select count(*)as RECORDCOUNT,"+"cast(null as boolean)as MYBOOL,"+"cast(null as int)as MYINT,"+"cast(null as char(1))as MYCHAR,"+"cast(null as smallint)as MYSMALLINT,"+"cast(null as varchar(1))as MYVARCHAR "+from_where
+"UNION ALL "//the "ALL" part prevents internal re-sorting to prevent duplicates (and we do not want that)+"select cast(null as int)as RECORDCOUNT,"+"MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR "+from_where);
Ihre Abfrageausgabe wird nun so etwas wie sein
1000nullnullnullnullnullnulltrue65537"Hey"-32768"The quick brown fox"nullfalse123456"Sup"300"The lazy dog"nullfalse-123123"Yo"0"Go ahead and jump"nullfalse3"EVH"456"Might as well jump"...[1001 total rows]
Also musst du einfach
if(rs.next())System.out.println("Recordcount: "+rs.getInt("RECORDCOUNT"));//hack: first record contains the record countwhile(rs.next())//do your stuff
Interessant, aber wie würden Sie dynamisch / generisch erste select-Anweisungen generieren: cast (null als Boolescher Wert) als MYBOOL, ect? Dazu benötigen Sie Metadaten der Felder und Datentypen der "select" -Anweisung (z. B. boolean, char, int, ect ...), für die möglicherweise eine zusätzliche DB-Auslösung erforderlich ist, die alle Vorteile zunichte macht.
user1697575
Dies ist nützlich, wenn Sie Zugriff auf alle Felddetails haben und die Geschwindigkeit Ihr Hauptanliegen ist (und daher bei einem schnellen bleiben müssen ResultSet.TYPE_FORWARD_ONLY)
Ich verstehe nicht, was der Nachteil der Verwendung dieser Methode zur Berechnung der ResultSet-Größe ist. Das ist großartig ... keine Verwendung eines zusätzlichen SQL-Parameters. Bitte kommentieren Sie diese Methode.
Madeyedexter
5
Leistung ist hier das Schlüsselwort. Stellen Sie sich vor, Ihre Ergebnismenge besteht aus 100 Millionen Datensätzen. Dann wird das Problem
Pierre,
7
Ich möchte die Größe der Ergebnismenge wissen, bevor ich die Ergebnisse verarbeite, da ich vorher ein Array mit derselben Größe erstellen muss. Und wie in anderen Antworten erwähnt, funktioniert das zweimalige Scannen aller Zeilen nicht immer.
Ivo
11
Ich habe eine Ausnahme bei der Verwendung rs.last()
Der Wechsel von ResultSet.TYPE_FORWARD_ONLYzu führt ResultSet.TYPE_SCROLL_INSENSITIVEnormalerweise zu einem enormen Leistungsverlust.
Unai Vivi
3
Ich habe es auf meiner Tabelle getestet (10 Spalten, 187 392 Zeilen). Mein Test hat alle Elemente abgefragt und in eine Zeichenfolge geladen. Für TYPE_FORWARD_ONLY dauerte es ca. 1 Sekunde. Für TYPE_SCROLL_INSENSITIVE dauerte es ca. 7 Sekunden. Als ich eher SELECT COUNT(*) FROM default_tblvor dem benutzte SELECT COUNT(*) FROM default_tbl, dauerte es insgesamt weniger als 1,5 Sekunden. Ich habe auf eingebetteten Derby-Datenbank 10.11.1.1
Vit Bernatik
4
Die Methode zum Abrufen der Größe von ResultSet, keine Verwendung von ArrayList usw.
int size =0;if(rs !=null){
rs.beforeFirst();
rs.last();
size = rs.getRow();}
Jetzt erhalten Sie die Größe. Wenn Sie das ResultSet drucken möchten, verwenden Sie vor dem Drucken auch die folgende Codezeile:
Viele Leute hier schlagen vor, ResultSet.last()aber dafür müssten Sie die Verbindung öffnen, da ResultSet.TYPE_SCROLL_INSENSITIVEdie für Derby eingebettete Datenbank bis zu 10-mal langsamer ist als ResultSet.TYPE_FORWARD_ONLY.
Laut meinen Mikrotests für eingebettete Derby- und H2-Datenbanken ist es wesentlich schneller, SELECT COUNT(*)vor Ihrem SELECT anzurufen .
Es ist eine einfache Möglichkeit, Zeilen zu zählen.
ResultSet rs = job.getSearchedResult(stmt);int rsCount =0;//but notice that you'll only get correct ResultSet size after end of the while loopwhile(rs.next()){//do your other per row stuff
rsCount = rsCount +1;}//end while
Ja, das funktioniert. Ich denke jedoch, dass das OP Schwierigkeiten hat, die Anzahl der Zeilen zu kennen, bevor sie tatsächlich verarbeitet werden. Gründe aus dem wirklichen Leben Ich müsste dieses Problem bisher bekämpfen: 1.) Blättern in Datensatzzeilen 2.)
Anzeigen
Die Vorbelegung der Datenstrukturgröße ist ein weiterer Grund. Ich habe gesehen, dass viele Bibliotheken 10 Elementlisten zurückgeben, wenn es nur einen einzigen Wert gibt, da die Entwickler das gleiche Problem mit ResultSet hatten.
Ich habe den Laufzeitwert der ResultSet- Schnittstelle überprüft und festgestellt, dass es sich die ganze Zeit über um ein ResultSetImpl handelt . ResultSetImpl hat eine Methode namens, getUpdateCount()die den gesuchten Wert zurückgibt.
Dieses Codebeispiel sollte ausreichen: ResultSet resultSet = executeQuery(sqlQuery); double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()
Mir ist klar, dass Downcasting im Allgemeinen ein unsicheres Verfahren ist, aber diese Methode hat mich noch nicht gescheitert.
Funktioniert nicht mit Tomcat / MySQL:java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.DelegatingResultSet cannot be cast to com.mysql.jdbc.ResultSetImpl
Panu Haaramo
1
Heute habe ich diese Logik verwendet, warum ich nicht weiß, wie man RS zählt.
int chkSize =0;if(rs.next()){do{..... blah blah
enter code here for each rs.
chkSize++;}while(rs.next());}else{
enter code here for rs size =0}// good luck to u.
theStatement=theConnection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);ResultSet theResult=theStatement.executeQuery(query);//Get the size of the data returned
theResult.last();int size = theResult.getRow()* theResult.getMetaData().getColumnCount();
theResult.beforeFirst();
Bewegt den Cursor in die erste Zeile dieses ResultSetObjekts.
Kehrt zurück:
truewenn sich der Cursor in einer gültigen Zeile befindet; falsewenn die Ergebnismenge keine Zeilen enthält
Würfe:
SQLException- wenn ein Datenbankzugriffsfehler auftritt; Diese Methode wird für eine geschlossene Ergebnismenge aufgerufen oder der Ergebnismengen-Typ istTYPE_FORWARD_ONLY
Am einfachsten ist es, die Abfrage Count (*) auszuführen, resultSet.next () auszuführen, um auf die erste Zeile zu zeigen, und dann einfach resultSet.getString (1) auszuführen, um die Anzahl abzurufen. Code:
ResultSet rs = statement.executeQuery("Select Count(*) from your_db");if(rs.next()){int count = rs.getString(1).toInt()}
Antworten:
SELECT COUNT(*) FROM ...
Führen Sie stattdessen eine Abfrage durch.ODER
In beiden Fällen müssen Sie nicht die gesamten Daten durchlaufen.
quelle
select count
?ResultSet#last()
funktioniert nicht bei allen Arten vonResultSet
Objekten, Sie müssen sicherstellen, dass Sie eines verwenden, das entwederResultSet.TYPE_SCROLL_INSENSITIVE
oderResultSet.TYPE_SCROLL_SENSITIVE
quelle
getRow()
funktioniert es fürTYPE_FORWARD_ONLY
ResultSets undbeforeFirst()
wirft Fehler für diese aus. Ist diese Antwort dann nicht fehlerhaft?ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
Nun, wenn Sie einen
ResultSet
Typ habenResultSet.TYPE_FORWARD_ONLY
, möchten Sie ihn so lassen (und nicht zu einemResultSet.TYPE_SCROLL_INSENSITIVE
oder wechseln,ResultSet.TYPE_SCROLL_INSENSITIVE
um ihn verwenden zu können.last()
).Ich schlage einen sehr schönen und effizienten Hack vor, bei dem Sie oben eine erste falsche / falsche Zeile hinzufügen, die die Anzahl der Zeilen enthält.
Beispiel
Angenommen, Ihre Anfrage lautet wie folgt
und Ihre Ausgabe sieht aus wie
Refaktorieren Sie Ihren Code einfach wie folgt:
Ihre Abfrageausgabe wird nun so etwas wie sein
Also musst du einfach
quelle
ResultSet.TYPE_FORWARD_ONLY
)quelle
Ich habe eine Ausnahme bei der Verwendung
rs.last()
::
Dies liegt standardmäßig daran
ResultSet.TYPE_FORWARD_ONLY
, was bedeutet, dass Sie nur verwenden könnenrs.next()
Die Lösung ist:
quelle
ResultSet.TYPE_FORWARD_ONLY
zu führtResultSet.TYPE_SCROLL_INSENSITIVE
normalerweise zu einem enormen Leistungsverlust.SELECT COUNT(*) FROM default_tbl
vor dem benutzteSELECT COUNT(*) FROM default_tbl
, dauerte es insgesamt weniger als 1,5 Sekunden. Ich habe auf eingebetteten Derby-Datenbank 10.11.1.1Die Methode zum Abrufen der Größe von ResultSet, keine Verwendung von ArrayList usw.
Jetzt erhalten Sie die Größe. Wenn Sie das ResultSet drucken möchten, verwenden Sie vor dem Drucken auch die folgende Codezeile:
quelle
[Geschwindigkeitsüberlegung]
Viele Leute hier schlagen vor,
ResultSet.last()
aber dafür müssten Sie die Verbindung öffnen, daResultSet.TYPE_SCROLL_INSENSITIVE
die für Derby eingebettete Datenbank bis zu 10-mal langsamer ist alsResultSet.TYPE_FORWARD_ONLY
.Laut meinen Mikrotests für eingebettete Derby- und H2-Datenbanken ist es wesentlich schneller,
SELECT COUNT(*)
vor Ihrem SELECT anzurufen .Hier finden Sie detaillierter meinen Code und meine Benchmarks
quelle
Es ist eine einfache Möglichkeit, Zeilen zu zählen.
quelle
quelle
Ich habe den Laufzeitwert der ResultSet- Schnittstelle überprüft und festgestellt, dass es sich die ganze Zeit über um ein ResultSetImpl handelt . ResultSetImpl hat eine Methode namens,
getUpdateCount()
die den gesuchten Wert zurückgibt.Dieses Codebeispiel sollte ausreichen:
ResultSet resultSet = executeQuery(sqlQuery);
double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()
Mir ist klar, dass Downcasting im Allgemeinen ein unsicheres Verfahren ist, aber diese Methode hat mich noch nicht gescheitert.
quelle
java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.DelegatingResultSet cannot be cast to com.mysql.jdbc.ResultSetImpl
Heute habe ich diese Logik verwendet, warum ich nicht weiß, wie man RS zählt.
quelle
quelle
Ich hatte das gleiche Problem. Verwenden Sie
ResultSet.first()
auf diese Weise direkt nach der Ausführung gelöst:Dokumentation ( Link ):
quelle
Am einfachsten ist es, die Abfrage Count (*) auszuführen, resultSet.next () auszuführen, um auf die erste Zeile zu zeigen, und dann einfach resultSet.getString (1) auszuführen, um die Anzahl abzurufen. Code:
quelle
Geben Sie der Spalte einen Namen.
Verweisen Sie auf diese Spalte aus dem ResultSet-Objekt in ein int und führen Sie von dort aus Ihre Logik aus.
quelle