如何获得java.sql.ResultSet的大小?

Jak*_*ake 276 java sql jdbc resultset record-count

这不应该是一个非常简单的操作吗?但是,我看到既没有size()也没有length()方法.

fin*_*nnw 259

SELECT COUNT(*) FROM ...改为查询.

要么

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

在任何一种情况下,您都不必遍历整个数据.

  • 为了简洁起见,我总是以这种方式引用方法,而不管它们是否是静态的.实际上创建了一个对象的实例并且隐含了调用该方法. (70认同)
  • 我编写了SomeClass.staticMethod()和SomeClass#instanceMethod()以减少混淆. (51认同)
  • `ResultSet#last()`不适用于所有类型的`ResultSet`对象,你需要确保使用的是`ResultSet.TYPE_SCROLL_INSENSITIVE`或`ResultSet.TYPE_SCROLL_SENSITIVE`. (15认同)
  • 如何获取执行"select count"时返回的值? (9认同)
  • last()和getRow()不是ResultSet类中的静态方法. (8认同)
  • @TK Kocheran,你可以得到任何一行/一列查询的结果,`executeQuery()`,`next()`和`getInt(1)` (4认同)
  • 有谁知道为什么得到结果集的计数是如此困难?为什么他们只在API中包含`ResultSet#size()`方法? (4认同)
  • 如果从存储过程调用返回结果集怎么办?事先没有办法知道它的大小吗? (2认同)

Jee*_*Bee 86

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
}
Run Code Online (Sandbox Code Playgroud)

  • 在if(rs.last())代码块中,不正确的方法是rs.beforeFirst()而不是rs.first()吗?这样,您不会跳过结果集中的第一条记录,以便在while循环中进行处理. (5认同)
  • 这仅在使用scroll insensitive选项创建语句时有效:`ps = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);` (2认同)

Una*_*ivi 19

好吧,如果你有一个ResultSet类型,ResultSet.TYPE_FORWARD_ONLY你想保持这种方式(而不是切换到ResultSet.TYPE_SCROLL_INSENSITIVEResultSet.TYPE_SCROLL_INSENSITIVE为了能够使用.last()).

我建议一个非常好的和有效的黑客,你在顶部添加第一个伪行/假行包含行数.

假设您的查询如下

select MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR
from MYTABLE
where ...blahblah...
Run Code Online (Sandbox Code Playgroud)

你的输出看起来像

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]
Run Code Online (Sandbox Code Playgroud)

只需将代码重构为以下内容:

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);
Run Code Online (Sandbox Code Playgroud)

您的查询输出现在将是这样的

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]
Run Code Online (Sandbox Code Playgroud)

所以你必须这样做

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


小智 10

使用时我遇到了异常 rs.last()

if(rs.last()){
    rowCount = rs.getRow(); 
    rs.beforeFirst();
}
Run Code Online (Sandbox Code Playgroud)

:

java.sql.SQLException: Invalid operation for forward only resultset
Run Code Online (Sandbox Code Playgroud)

它是默认的ResultSet.TYPE_FORWARD_ONLY,这意味着你只能使用rs.next()

解决方案是:

stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY); 
Run Code Online (Sandbox Code Playgroud)

  • 从`ResultSet.TYPE_FORWARD_ONLY`切换到`ResultSet.TYPE_SCROLL_INSENSITIVE'通常会导致**巨大的**性能损失. (11认同)
  • 我在我的桌子上测试了它(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 (3认同)

小智 10

int i = 0;
while(rs.next()) {
    i++;
}
Run Code Online (Sandbox Code Playgroud)

  • 我想在处理结果之前知道结果集大小,因为我需要事先制作一个大小相同的数组.而且,正如其他答案所述,扫描所有行两次并不总是有效. (7认同)
  • Performance是这里的关键字.想象一下你的结果集是100M记录然后你会看到问题 (5认同)

Vit*_*tik 5

【速度考虑】

这里的脂肪酶很多建议ResultSet.last(),但对于您需要打开的连接的ResultSet.TYPE_SCROLL_INSENSITIVE这对德比嵌入式数据库是高达10倍速度较慢ResultSet.TYPE_FORWARD_ONLY

根据我对嵌入式 Derby 和 H2 数据库的微测试,SELECT COUNT(*)在 SELECT 之前调用要快得多。

这是我的代码和基准测试的更详细信息