ฉันจะรับขนาดของ java.sql.ResultSet ได้อย่างไร


285

นี่ไม่ควรเป็นการผ่าตัดที่ตรงไปตรงมาใช่หรือไม่ อย่างไรก็ตามฉันเห็นว่าไม่มีทั้งวิธีsize()และlength()วิธีการ


11
ฉันชอบที่จะรู้เหตุผลของการละเลยนั้น
Slamice

ความเข้าใจในคำถามของฉันคือคุณต้องการหาขนาดของ ResultSet ใน BYTES ไม่ใช่จำนวนของ tuples ...
DejanLekic

มันน่ารำคาญมากที่จะมีไม่ได้เป็นมิติทางด้านขวาก่อนที่จะประมวลผลข้อมูล แต่ถ้าคุณต้องเก็บไว้ในอาร์เรย์คุณสามารถพิจารณาใช้โครงสร้างข้อมูลเช่นรายการและจากนั้นแปลงให้อาร์เรย์กับ toArray () วิธีการ
AndreaTaroni86

คำตอบ:


270

ทำSELECT COUNT(*) FROM ...แบบสอบถามแทน

หรือ

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

ไม่ว่าในกรณีใดคุณไม่จำเป็นต้องวนซ้ำข้อมูลทั้งหมด


8
last () และ getRow () ไม่ใช่วิธีการคงที่ในคลาส ResultSet
JeeBee

70
เพื่อประโยชน์ของความกะทัดรัดฉันมักจะอ้างอิงวิธีการในแบบนี้เมื่อเขียนเกี่ยวกับพวกเขาให้ผู้อื่นโดยไม่คำนึงว่าพวกเขาจะคงที่หรือไม่ อันที่จริงการสร้างอินสแตนซ์ของวัตถุและเรียกวิธีการบอกเป็นนัย ๆ
laz

51
ฉันเขียน SomeClass.staticMethod () และ SomeClass # instanceMethod () เพื่อความสับสนน้อยลง
เจค

9
หนึ่งในวิธีการที่ไม่สามารถดึงข้อมูลค่าส่งกลับเมื่อดำเนินการselect count?
Naftuli Kay

16
ResultSet#last()ไม่ทำงานกับResultSetวัตถุทุกประเภทคุณต้องตรวจสอบให้แน่ใจว่าคุณใช้วัตถุที่มีResultSet.TYPE_SCROLL_INSENSITIVEหรือResultSet.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
ภายใน if (rs.last ()) การป้องกันรหัสจะไม่ใช่วิธีที่ถูกต้องจะ rs.beforeFirst () แทน rs.first ()? ด้วยวิธีนี้คุณจะไม่ข้ามระเบียนแรกในชุดผลลัพธ์ของคุณสำหรับการประมวลผลในขณะที่ลูป
karlgrz

คุณไม่ลืมที่จะตั้งค่าเคอร์เซอร์กลับไปก่อนก่อนนอกบล็อก?
Gobliins

ดังที่เอกสาร ResultSetบอกว่าใช้getRow()งานได้กับTYPE_FORWARD_ONLYResultSets และส่งbeforeFirst()ข้อผิดพลาดให้ นี่ไม่ใช่คำตอบที่ผิดหรือเปล่า?
CodePro_NotYet

5
ใช้งานได้เฉพาะเมื่อสร้างคำสั่งด้วยตัวเลือกที่ไม่ไวต่อการเลื่อน:ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
BullyWiiPlaza

19

ดีถ้าคุณมีResultSetประเภทที่ResultSet.TYPE_FORWARD_ONLYคุณต้องการให้เป็นเช่นนั้น (และไม่เปลี่ยนเป็นResultSet.TYPE_SCROLL_INSENSITIVEหรือResultSet.TYPE_SCROLL_INSENSITIVEเพื่อให้สามารถใช้.last())

ฉันแนะนำแฮ็คที่ดีและมีประสิทธิภาพซึ่งคุณเพิ่มแถวปลอม / แถวปลอมที่ด้านบนสุดที่มีจำนวนแถว

ตัวอย่าง

สมมติว่าคำค้นหาของคุณมีดังต่อไปนี้

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

และผลลัพธ์ของคุณดูเหมือน

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]

เพียงปรับรหัสของคุณเป็นแบบนี้:

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

ผลลัพธ์ข้อความค้นหาของคุณจะเป็นเช่นนี้

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]

ดังนั้นคุณต้อง

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

ที่น่าสนใจ แต่คุณจะสร้างงบเลือกแรกแบบไดนามิกอย่างไร: cast (null เป็นบูลีน) เป็น MYBOOL, ect เพื่อที่คุณจะต้องมีเมทาดาทาของฟิลด์คำสั่ง "เลือก" และประเภทข้อมูลเช่นบูลีน, ถ่าน, int, ect ... ) ที่อาจต้องใช้การเดินทาง DB พิเศษที่จะคัดค้านผลประโยชน์ทั้งหมด
user1697575

สิ่งนี้มีประโยชน์เมื่อคุณเข้าถึงรายละเอียดทุกฟิลด์และความเร็วเป็นข้อกังวลหลักของคุณ (และดังนั้นจึงจำเป็นต้องดำเนินการอย่างรวดเร็วResultSet.TYPE_FORWARD_ONLY)
Unai Vivi

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

ฉันไม่เข้าใจข้อเสียเปรียบของการใช้วิธีนี้ในการคำนวณขนาด ResultSet นี้เป็นที่ดี ... ใช้พารามิเตอร์ SQL เสริม โปรดแสดงความคิดเห็นเกี่ยวกับวิธีการนี้
Madeyedexter

5
ประสิทธิภาพเป็นคำหลักที่นี่ ลองนึกภาพ resultset ของคุณเป็น 100M บันทึกแล้วคุณจะเห็นปัญหา
ปิแอร์

7
ฉันต้องการทราบขนาดชุดผลลัพธ์ก่อนที่จะประมวลผลผลลัพธ์เพราะฉันจำเป็นต้องสร้างอาร์เรย์ที่มีขนาดเท่ากันก่อน และตามที่ระบุไว้ในคำตอบอื่น ๆ การสแกนแถวทั้งหมดสองครั้งจะไม่ทำงาน
Ivo

11

ผมได้รับข้อยกเว้นเมื่อมีการใช้ rs.last()

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

:

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

มันเกิดจากการเริ่มต้นมันเป็นResultSet.TYPE_FORWARD_ONLYซึ่งหมายความว่าคุณสามารถใช้ได้rs.next()

การแก้ปัญหาคือ:

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

12
เปลี่ยนจากResultSet.TYPE_FORWARD_ONLYการResultSet.TYPE_SCROLL_INSENSITIVEมักจะเกิดขึ้นในขนาดใหญ่ลงโทษประสิทธิภาพ
Unai Vivi

3
ฉันทดสอบบนโต๊ะของฉัน (10 คอลัมน์ 187 392 แถว) การทดสอบของฉันทำการสืบค้นและโหลดองค์ประกอบทั้งหมดลงในสตริง สำหรับ TYPE_FORWARD_ONLY ใช้เวลาประมาณ 1 วินาที สำหรับ TYPE_SCROLL_INSENSITIVE ใช้เวลาประมาณ 7 วินาที เมื่อฉันใช้SELECT COUNT(*) FROM default_tblก่อนหน้าSELECT COUNT(*) FROM default_tblนี้มันใช้เวลาทั้งหมดน้อยกว่า 1.5 วินาที ฉันทดสอบบนฐานข้อมูลดาร์บี้แบบฝังตัว 10.11.1.1
Vit Bernatik

4

วิธีการรับขนาดของ ResultSet ไม่จำเป็นต้องใช้ ArrayList ฯลฯ

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

ตอนนี้คุณจะได้ขนาดและถ้าคุณต้องการพิมพ์ ResultSet ก่อนที่จะพิมพ์ให้ใช้บรรทัดของรหัสต่อไปนี้ด้วย

rs.beforeFirst();  

4

[การพิจารณาความเร็ว]

ล็อตของ ppl นี่แสดงให้เห็นResultSet.last()แต่การที่คุณจะต้องเปิดการเชื่อมต่อเป็นResultSet.TYPE_SCROLL_INSENSITIVEฐานข้อมูลที่ดาร์บี้ฝังตัวได้ถึง 10 เท่าช้าResultSet.TYPE_FORWARD_ONLYกว่า

จากการทดสอบไมโครของฉันสำหรับฐานข้อมูล Derby และ H2 แบบฝังตัวมันจะเร็วกว่าการโทรSELECT COUNT(*)ก่อนเลือกของคุณ

นี่คือรายละเอียดเพิ่มเติมรหัสและมาตรฐานของฉัน


3

มันเป็นวิธีง่ายๆในการนับแถว

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
ใช่ว่างาน แต่ผมคิดว่าการต่อสู้กับ OP รู้จำนวนแถวก่อนที่จริงการประมวลผลให้พวกเขา เหตุผลในชีวิตจริงฉันต้องต่อสู้กับปัญหานี้จนถึง: 1. ) การเพจของแถวเรคคอร์ด 2. ) แสดงแถวที่ถูกประมวลผลในงานที่ต้องใช้เวลานานเพื่อจุดประสงค์ในการตรวจสอบความคืบหน้า ...
ppeterka

การกำหนดขนาดโครงสร้างข้อมูลล่วงหน้าเป็นอีกสาเหตุหนึ่ง ผมเคยเห็นความอุดมสมบูรณ์ของ libs กลับ 10 รายการองค์ประกอบเมื่อมีเพียงค่าเดียวเพราะของ dev มีปัญหาเดียวกันนี้กับ ResultSet
โจเซฟ 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

ฉันตรวจสอบค่ารันไทม์ของอินเตอร์เฟสResultSetและพบว่าเป็นResultSetImplเกือบตลอดเวลา ResultSetImpl มีวิธีการที่เรียกว่าgetUpdateCount()คืนค่าที่คุณกำลังมองหา

ตัวอย่างโค้ดนี้ควรเพียงพอ:
ResultSet resultSet = executeQuery(sqlQuery);
double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()

ฉันรู้ว่าการดาวน์สตรีมโดยทั่วไปเป็นขั้นตอนที่ไม่ปลอดภัย แต่วิธีนี้ยังไม่ทำให้ฉันล้มเหลว


2
ไม่ทำงานกับ Tomcat / MySQL:java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.DelegatingResultSet cannot be cast to com.mysql.jdbc.ResultSetImpl
Panu Haaramo

1

วันนี้ฉันใช้ตรรกะนี้ว่าทำไมฉันจึงไม่ทราบว่าการนับ 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

ฉันมีปัญหาเดียวกัน การใช้ResultSet.first()วิธีนี้หลังจากการประมวลผลแก้ไขได้:

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

เอกสาร ( ลิงค์ ):

boolean first()
    throws SQLException

เลื่อนเคอร์เซอร์ไปยังแถวแรกในครั้งนี้ResultSetวัตถุ

ผลตอบแทน:

trueหากเคอร์เซอร์อยู่ในแถวที่ถูกต้อง falseหากไม่มีแถวในชุดผลลัพธ์

โยน:

SQLException- หากเกิดข้อผิดพลาดในการเข้าถึงฐานข้อมูล วิธีการนี้เรียกว่าในชุดผลลัพธ์ที่ปิดหรือประเภทชุดผลลัพธ์คือTYPE_FORWARD_ONLY

SQLFeatureNotSupportedException - หากไดรเวอร์ JDBC ไม่รองรับวิธีนี้

ตั้งแต่:

1.2


0

วิธีที่ง่ายที่สุด, เรียกใช้คิวรีนับ (*), ทำ resultSet.next () เพื่อชี้ไปที่แถวแรกจากนั้นเพียงทำ resultSet.getString (1) เพื่อรับจำนวน รหัส:

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

-1

ตั้งชื่อคอลัมน์ ..

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

อ้างอิงคอลัมน์นั้นจากอ็อบเจกต์ ResultSet ไปยัง int และทำลอจิกของคุณจากที่นั่น ..

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.");
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.