Jak uzyskać rozmiar java.sql.ResultSet?


285

Czy nie powinna to być dość prosta operacja? Widzę jednak, że nie ma metody size()nor length().


11
Chciałbym poznać przyczynę tego pominięcia.
— Slamice,

Zrozumiałem pytanie, że chcesz znaleźć rozmiar zestawu wyników w bajtach, a nie liczbę krotek ...
— DejanLekic

Bardzo denerwujące jest to, że nie ma właściwego wymiaru przed przetwarzaniem danych, ale jeśli musisz przechowywać je w tablicy, możesz rozważyć użycie struktury danych takiej jak List, a następnie przekonwertować je na tablicę za pomocą metody toArray ().
— AndreaTaroni86

Odpowiedzi:


270

SELECT COUNT(*) FROM ...Zamiast tego wykonaj zapytanie.

LUB

int size =0;
if (rs != null) 
{
  rs.last();    // moves cursor to the last row
  size = rs.getRow(); // get row id 
}

W obu przypadkach nie będziesz musiał zapętlać całych danych.


8
last () i getRow () nie są metodami statycznymi w klasie ResultSet.
— JeeBee,

70
Dla zwięzłości zawsze piszę o metodach w ten sposób, pisząc o nich innym, bez względu na to, czy są one statyczne, czy nie. W rzeczywistości zakłada się utworzenie instancji obiektu i wywołanie metody.
— laz

51
Piszę SomeClass.staticMethod () i SomeClass # instanceMethod () dla mniejszego zamieszania.
— Jake

9
Jak pobrać wartość zwróconą podczas wykonywania select count?
— Naftuli Kay

16
ResultSet#last()nie działa na wszystkich typach ResultSetobiektów, musisz upewnić się, że używasz jednego z nich ResultSet.TYPE_SCROLL_INSENSITIVElubResultSet.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
}

5
Czy w bloku kodu if (rs.last ()) poprawną metodą nie byłoby rs.beforeFirst () zamiast rs.first ()? W ten sposób nie pomijasz pierwszego rekordu w zestawie wyników do przetwarzania w pętli while.
— karlgrz

nie zapomnij ustawić z powrotem kursora na pozycję Pierwsze na zewnątrz bloku if?
— Gobliins,

Jak mówią dokumenty ResultSet , getRow()działa dla TYPE_FORWARD_ONLYResultSets i beforeFirst()zgłasza dla nich błędy. Czy więc ta odpowiedź nie jest błędna?
— CodePro_NotYet

5
Działa to tylko wtedy, gdy instrukcja jest tworzona z opcją niewrażliwą na przewijanie:ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
— BullyWiiPlaza

19

Cóż, jeśli masz ResultSettypu ResultSet.TYPE_FORWARD_ONLYchcesz zachować to w ten sposób (i nie przełączyć się na ResultSet.TYPE_SCROLL_INSENSITIVElub ResultSet.TYPE_SCROLL_INSENSITIVEw celu umożliwienia użytkowania .last()).

Sugeruję bardzo fajny i wydajny hack, w którym dodajesz pierwszy fałszywy / fałszywy wiersz na górze zawierający liczbę wierszy.

Przykład

Powiedzmy, że twoje zapytanie jest następujące

select MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR
from MYTABLE
where ...blahblah...

a twój wygląd wygląda

true    65537 "Hey" -32768 "The quick brown fox"
false  123456 "Sup"    300 "The lazy dog"
false -123123 "Yo"       0 "Go ahead and jump"
false       3 "EVH"    456 "Might as well jump"
...
[1000 total rows]

Po prostu popraw kod na coś takiego:

Statement s=myConnection.createStatement(ResultSet.TYPE_FORWARD_ONLY,
                                         ResultSet.CONCUR_READ_ONLY);
String from_where="FROM myTable WHERE ...blahblah... ";
//h4x
ResultSet 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);

Dane wyjściowe zapytania będą teraz podobne

1000 null     null null    null null
null true    65537 "Hey" -32768 "The quick brown fox"
null false  123456 "Sup"    300 "The lazy dog"
null false -123123 "Yo"       0 "Go ahead and jump"
null false       3 "EVH"    456 "Might as well jump"
...
[1001 total rows]

Musisz po prostu

if(rs.next())
    System.out.println("Recordcount: "+rs.getInt("RECORDCOUNT"));//hack: first record contains the record count
while(rs.next())
    //do your stuff

Ciekawe, ale jak byś generował dynamicznie / generalnie pierwsze instrukcje select: cast (null as boolean) jako MYBOOL, ect? W tym celu potrzebujesz metadanych pól i typów danych instrukcji „select”, takich jak boolean, char, int, ect ...), które mogą wymagać dodatkowej podróży DB, która neguje wszystkie korzyści.
— user1697575,

Jest to przydatne, gdy masz dostęp do wszystkich szczegółów pola, a najważniejsza jest prędkość (i dlatego musisz trzymać się postu ResultSet.TYPE_FORWARD_ONLY)
— Unai Vivi

11
int i = 0;
while(rs.next()) {
    i++;
}

Nie rozumiem, jaka jest wada używania tej metody do obliczania rozmiaru zestawu wyników. To wspaniale ... bez użycia dodatkowego parametru SQL. Proszę skomentować tę metodę.
— Madeyedexter

5
Wydajność jest tutaj słowem kluczowym. Wyobraź sobie, że Twój zestaw wyników to 100 milionów rekordów, a wtedy zobaczysz problem
— Pierre,

7
Chcę poznać rozmiar zestawu wyników PRZED przetworzeniem wyników, ponieważ muszę wcześniej utworzyć tablicę o tym samym rozmiarze. I, jak zauważono w innych odpowiedziach, skanowanie wszystkich wierszy dwa razy nie zawsze będzie działać.
— Ivo

11

Mam wyjątek podczas używania rs.last()

if(rs.last()){
    rowCount = rs.getRow(); 
    rs.beforeFirst();
}

:

java.sql.SQLException: Invalid operation for forward only resultset

jest to spowodowane domyślnie ResultSet.TYPE_FORWARD_ONLY, co oznacza, że ​​możesz używać tylkors.next()

rozwiązaniem jest:

stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY); 

12
Przełączanie z ResultSet.TYPE_FORWARD_ONLYna ResultSet.TYPE_SCROLL_INSENSITIVEogół pociąga za sobą w wielkim spadku wydajności.
— Unai Vivi

3
Testowałem to na moim stole (10 kolumn, 187 392 wierszy). Mój test wykonał zapytanie i załadował wszystkie elementy do łańcucha. Dla TYPE_FORWARD_ONLY zajęło to około 1 sekundy. Dla TYPE_SCROLL_INSENSITIVE zajęło to około 7 sekund. Kiedy użyłem SELECT COUNT(*) FROM default_tblwcześniej SELECT COUNT(*) FROM default_tbl, zajęło to mniej niż 1,5 sekundy. Testowałem na wbudowanej bazie danych derby 10.11.1.1
— Vit Bernatik

4

Sposób uzyskania rozmiaru ResultSet, nie ma potrzeby używania ArrayList itp

int size =0;  
if (rs != null)   
{  
rs.beforeFirst();  
 rs.last();  
size = rs.getRow();
}

Teraz otrzymasz rozmiar, a jeśli chcesz wydrukować zestaw wyników, przed wydrukowaniem użyj również następującego wiersza kodu,

rs.beforeFirst();  

4

[Uwzględnienie prędkości]

Wiele ppl tutaj sugeruje, ResultSet.last()ale do tego trzeba by otworzyć połączenie, ponieważ ResultSet.TYPE_SCROLL_INSENSITIVEdla wbudowanej bazy danych Derby jest do 10 razy wolniejsze niż ResultSet.TYPE_FORWARD_ONLY.

Według moich mikrotestów dla osadzonych baz danych Derby i H2 znacznie szybciej jest zadzwonić SELECT COUNT(*)przed SELECT.

Oto bardziej szczegółowo mój kod i moje testy porównawcze


3

Jest to prosty sposób na liczenie wierszy.

ResultSet rs = job.getSearchedResult(stmt);
int rsCount = 0;

//but notice that you'll only get correct ResultSet size after end of the while loop
while(rs.next())
{
    //do your other per row stuff 
    rsCount = rsCount + 1;
}//end while

4
Tak, to działa. Ale myślę, że OP boryka się ze znajomością liczby wierszy, zanim faktycznie je przetworzy. Prawdziwe powody, dla których musiałbym do tej pory walczyć z tym problemem: 1.) stronicowanie rekordowych wierszy 2.) pokazywanie wierszy przetworzonych w długo trwających zadaniach do celów monitorowania postępów ...
— ppeterka

Innym powodem jest wstępne przydzielanie wielkości struktury danych. Widziałem, że wiele bibliotek zwraca 10 list Element, gdy jest tylko jedna wartość, ponieważ deweloper miał ten sam problem z ResultSet.
— Joseph Lust

2
String sql = "select count(*) from message";
ps =  cn.prepareStatement(sql);

rs = ps.executeQuery();
int rowCount = 0;
while(rs.next()) {
    rowCount = Integer.parseInt(rs.getString("count(*)"));
    System.out.println(Integer.parseInt(rs.getString("count(*)")));
}
System.out.println("Count : " + rowCount);

1

Sprawdziłem wartość środowiska uruchomieniowego interfejsu ResultSet i odkryłem, że przez cały czas była to w zasadzie ResultSetImpl . ResultSetImpl ma wywoływaną metodę, getUpdateCount()która zwraca poszukiwaną wartość.

Ten przykładowy kod powinien wystarczyć:
ResultSet resultSet = executeQuery(sqlQuery);
double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()

Zdaję sobie sprawę, że downcasting jest ogólnie niebezpieczną procedurą, ale ta metoda jeszcze mnie nie zawiodła.


2
Nie działa z Tomcat / MySQL:java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.DelegatingResultSet cannot be cast to com.mysql.jdbc.ResultSetImpl
— Panu Haaramo

1

Dzisiaj użyłem tej logiki, dlaczego nie wiem, jak uzyskać liczbę RS.

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.

0
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();

0

Miałem ten sam problem. Używając ResultSet.first()w ten sposób zaraz po rozwiązaniu wykonania:

if(rs.first()){
    // Do your job
} else {
    // No rows take some actions
}

Dokumentacja ( link ):

boolean first()
    throws SQLException

Przenosi kursor do pierwszego wiersza w tym ResultSetobiekcie.

Zwroty:

truejeśli kursor znajduje się w poprawnym wierszu; falsejeśli nie ma wierszy w zestawie wyników

Rzuty:

SQLException- jeśli wystąpi błąd dostępu do bazy danych; ta metoda jest wywoływana dla zamkniętego zestawu wyników lub typem zestawu wyników jestTYPE_FORWARD_ONLY

SQLFeatureNotSupportedException - jeśli sterownik JDBC nie obsługuje tej metody

Od:

1.2


0

Najłatwiejsze podejście, zapytanie Run Count (*), wykonaj resultSet.next (), aby wskazać pierwszy wiersz, a następnie po prostu wykonaj wynikSet.getString (1), aby uzyskać liczbę. Kod :

ResultSet rs = statement.executeQuery("Select Count(*) from your_db");
if(rs.next()) {
   int count = rs.getString(1).toInt()
}

-1

Nadaj kolumnie nazwę…

String query = "SELECT COUNT(*) as count FROM

Odwołaj się do tej kolumny z obiektu ResultSet do int i wykonaj swoją logikę stamtąd.

PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, item.getProductId());
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
    int count = resultSet.getInt("count");
    if (count >= 1) {
        System.out.println("Product ID already exists.");
    } else {
        System.out.println("New Product ID.");
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.