Làm cách nào để tôi có được kích thước của java.sql.ResultSet?


284

Đây không phải là một hoạt động khá đơn giản? Tuy nhiên, tôi thấy có phải là một size()hay length()phương pháp.


11
Tôi rất muốn biết lý do cho sự thiếu sót đó.
Slamice

Sự hiểu biết của tôi về câu hỏi là bạn muốn tìm kích thước của Bộ kết quả TRONG BYTES, chứ không phải số bộ dữ liệu ...
DejanLekic

Thật khó chịu khi không có kích thước phù hợp trước khi xử lý dữ liệu, nhưng nếu bạn phải lưu trữ chúng trong một mảng, bạn có thể xem xét sử dụng cấu trúc dữ liệu như Danh sách và sau đó chuyển đổi chúng thành một mảng bằng phương thức toArray ().
AndreaTaroni86

Câu trả lời:


270

Thực hiện một SELECT COUNT(*) FROM ...truy vấn thay thế.

HOẶC LÀ

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

Trong cả hai trường hợp, bạn sẽ không phải lặp lại toàn bộ dữ liệu.


8
last () và getRow () không phải là các phương thức tĩnh trong lớp result Set.
JeeBee

70
Vì lý do ngắn gọn, tôi luôn tham khảo các phương pháp theo cách này khi viết về chúng cho người khác, bất kể chúng có tĩnh hay không. Trên thực tế việc tạo một thể hiện của đối tượng và gọi phương thức được ngụ ý.
laz

51
Tôi viết someClass.staticMethod () và someClass # instanceMethod () để ít nhầm lẫn hơn.
Jake

9
Làm thế nào để lấy giá trị trả về khi thực hiện a select count?
Naftuli Kay

16
ResultSet#last()không hoạt động trên tất cả các loại ResultSetđối tượng, bạn cần đảm bảo rằng bạn sử dụng một trong hai ResultSet.TYPE_SCROLL_INSENSITIVEhoặcResultSet.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
Bên trong khối mã if (rs.last ()), phương thức đúng có phải là rs.b BeforeFirst () thay vì rs.first () không? Bằng cách này, bạn không bỏ qua bản ghi đầu tiên trong tập kết quả của mình để xử lý trong vòng lặp while.
karlgrz

bạn không quên đặt con trỏ trở lại trướcFirst bên ngoài khối if?
Yêu tinh

Như các tài liệu của result Set nói, getRow()hoạt động cho các Kết quả TYPE_FORWARD_ONLYbeforeFirst()đưa ra các lỗi cho những kết quả đó. Không phải câu trả lời này là sai rồi sao?
CodePro_NotYet

5
Điều này chỉ hoạt động khi câu lệnh được tạo với tùy chọn không nhạy cảm cuộn:ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
BullyWiiPlaza

19

Chà, nếu bạn có một ResultSetloại ResultSet.TYPE_FORWARD_ONLYbạn muốn giữ nó theo cách đó (và không chuyển sang một ResultSet.TYPE_SCROLL_INSENSITIVEhoặc ResultSet.TYPE_SCROLL_INSENSITIVEđể có thể sử dụng .last()).

Tôi đề nghị một hack rất hay và hiệu quả, trong đó bạn thêm một hàng giả / giả mạo đầu tiên ở đầu chứa số lượng hàng.

Thí dụ

Giả sử truy vấn của bạn là như sau

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

và đầu ra của bạn trông giống như

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]

Đơn giản chỉ cần cấu trúc lại mã của bạn thành một cái gì đó như thế này:

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

Đầu ra truy vấn của bạn sẽ giống như

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]

Vì vậy, bạn chỉ cần phải

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

Thú vị, nhưng làm thế nào bạn có thể tạo ra các câu lệnh chọn đầu tiên: cast (null as boolean) như MYBOOL, ect? Vì vậy, bạn sẽ cần siêu dữ liệu của các trường và kiểu dữ liệu của câu lệnh "select", như boolean, char, int, ect ...) có thể yêu cầu thêm chuyến đi DB sẽ phủ nhận tất cả các lợi ích.
dùng1697575

Điều này hữu ích khi bạn có quyền truy cập vào tất cả các chi tiết và tốc độ trường là mối quan tâm chính của bạn (và do đó cần phải nhanh chóng ResultSet.TYPE_FORWARD_ONLY)
Unai Vivi

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

Tôi không hiểu nhược điểm của việc sử dụng phương pháp này là gì để tính toán kích thước Kết quả. Điều này thật tuyệt ... không sử dụng thêm một tham số SQL. Hãy bình luận về phương pháp này.
Madeyedexter 13/03/2015

5
Hiệu suất là từ khóa ở đây. Hãy tưởng tượng kết quả của bạn là 100 triệu bản ghi thì bạn sẽ thấy vấn đề
Pierre

7
Tôi muốn biết kích thước tập kết quả TRƯỚC KHI xử lý kết quả vì tôi cần tạo một mảng có cùng kích thước trước đó. Và, như đã lưu ý trong các câu trả lời khác, quét tất cả các hàng hai lần sẽ không luôn hoạt động.
Ivo

11

Tôi có một ngoại lệ khi sử dụng rs.last()

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

:

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

Theo mặc định ResultSet.TYPE_FORWARD_ONLY, đó là do bạn chỉ có thể sử dụngrs.next()

giải pháp là:

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

12
Chuyển từ ResultSet.TYPE_FORWARD_ONLYđể ResultSet.TYPE_SCROLL_INSENSITIVEthường phải gánh chịu trong một khổng lồ hình phạt hiệu quả.
Unai Vivi

3
Tôi đã kiểm tra nó trên bàn của tôi (10 cột, 187 392 hàng). Thử nghiệm của tôi đã truy vấn và tải tất cả các yếu tố vào chuỗi. Đối với TYPE_FORWARD_ONLY, mất khoảng 1 giây. Đối với TYPE_SCROLL_INSENSITIVE, mất khoảng 7 giây. Khi tôi sử dụng thay vì SELECT COUNT(*) FROM default_tbltrước SELECT COUNT(*) FROM default_tblđó, nó chỉ mất chưa đến 1,5 giây. Tôi đã thử nghiệm trên cơ sở dữ liệu derby nhúng 10.11.1.1
Vit Bernatik

4

Cách lấy kích thước của Kết quả, Không cần sử dụng ArrayList, v.v.

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

Bây giờ Bạn sẽ nhận được kích thước, và nếu bạn muốn in Kết quả, trước khi in, hãy sử dụng dòng mã sau đây,

rs.beforeFirst();  

4

[Xem xét tốc độ]

Rất nhiều ppl ở đây gợi ý ResultSet.last()nhưng đối với điều đó, bạn sẽ cần phải mở kết nối vì ResultSet.TYPE_SCROLL_INSENSITIVEcơ sở dữ liệu nhúng của Derby gấp 10 lần SLOWER so vớiResultSet.TYPE_FORWARD_ONLY .

Theo các bài kiểm tra vi mô của tôi đối với cơ sở dữ liệu Derby và H2 được nhúng, việc gọi nhanh hơn đáng kể SELECT COUNT(*) trước CHỌN của bạn .

Dưới đây là chi tiết hơn mã của tôi và điểm chuẩn của tôi


3

Đây là một cách đơn giản để đếm hàng.

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
Vâng, nó hoạt động. Nhưng tôi nghĩ OP đấu tranh với việc biết số lượng hàng trước khi thực sự xử lý chúng. Cho đến nay, lý do thực tế tôi phải chống lại vấn đề này: 1.) phân trang các hàng ghi 2.) hiển thị các hàng được xử lý trong các tác vụ dài hạn cho mục đích theo dõi tiến độ ...
ppeterka

Kích thước cấu trúc dữ liệu preallocating là một lý do khác. Tôi đã thấy rất nhiều lib trả về 10 phần tử Danh sách khi chỉ có một giá trị duy nhất vì nhà phát triển có vấn đề tương tự với Kết quả.
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

Tôi đã kiểm tra các giá trị thời gian chạy của ResultSet giao diện và phát hiện ra nó đã được khá nhiều một ResultSetImpl tất cả các thời gian. ResultInImpl có một phương thức gọi là getUpdateCount()trả về giá trị mà bạn đang tìm kiếm.

Mẫu mã này phải đủ:
ResultSet resultSet = executeQuery(sqlQuery);
double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()

Tôi nhận ra rằng downcasting nói chung là một quy trình không an toàn nhưng phương pháp này vẫn chưa làm tôi thất bại.


2
Không hoạt động với Tomcat / MySQL:java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.DelegatingResultSet cannot be cast to com.mysql.jdbc.ResultSetImpl
Panu Haaramo

1

Hôm nay, tôi đã sử dụng logic này tại sao tôi không biết việc đếm 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

Tôi đã có cùng một vấn đề. Sử dụng ResultSet.first()theo cách này ngay sau khi thực hiện đã giải quyết nó:

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

Tài liệu ( liên kết ):

boolean first()
    throws SQLException

Di chuyển con trỏ đến hàng đầu tiên trong ResultSetđối tượng này .

Trả về:

truenếu con trỏ ở trên một hàng hợp lệ; falsenếu không có hàng trong tập kết quả

Ném:

SQLException- nếu xảy ra lỗi truy cập cơ sở dữ liệu; phương thức này được gọi trên tập kết quả đóng hoặc kiểu tập kết quả làTYPE_FORWARD_ONLY

SQLFeatureNotSupportedException - nếu trình điều khiển JDBC không hỗ trợ phương thức này

Từ:

1.2


0

Cách tiếp cận dễ nhất, truy vấn Run Count (*), thực hiện resultset.next () để trỏ đến hàng đầu tiên và sau đó chỉ cần thực hiện resultset.getString (1) để lấy số đếm. Mã số:

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

-1

Đặt tên cho cột ..

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

Tham chiếu cột đó từ đối tượng result Set thành một int và thực hiện logic của bạn từ đó ..

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.");
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.