如何在 Java 中使用 ResultSet 获取行数?

Posted

技术标签:

【中文标题】如何在 Java 中使用 ResultSet 获取行数?【英文标题】:How to get row count using ResultSet in Java? 【发布时间】:2011-12-14 17:56:04 【问题描述】:

我正在尝试创建一个简单的方法,它接收一个 ResultSet 作为参数并返回一个包含 ResultSet 行数的 int。这是一种有效的方式吗?

int size = 0;
    try 
        while(rs.next())
            size++;
        
    
    catch(Exception ex) 
        System.out.println("------------------Tablerize.getRowCount-----------------");
        System.out.println("Cannot get resultSet row count: " + ex);
        System.out.println("--------------------------------------------------------");
    

我试过了:

int size = 0;
try 
    resultSet.last();
    size = resultSet.getRow();
    resultSet.beforeFirst();

catch(Exception ex) 
    return 0;

return size;

但我收到一条错误消息,提示 com.microsoft.sqlserver.jdbc.SQLServerException: The requested operation is not supported on forward only result sets.

提前感谢指点!

【问题讨论】:

不能把sql语句改成SELECT COUNT(*) ...吗? 为什么在调用填充结果集的查询之前不执行“select count(*)”?但是 ForwardOnly RS 取决于您打开连接的方式(需要传递一些参数)。查看您的 jdbc 驱动程序文档了解详细信息。 (OT;您可能需要考虑使用实际的日志库来处理诸如输出方法名称等事情) 【参考方案1】:
Statement s = cd.createStatement();
ResultSet r = s.executeQuery("SELECT COUNT(*) AS rowcount FROM FieldMaster");
r.next();
int count = r.getInt("rowcount");
r.close();
System.out.println("MyTable has " + count + " row(s).");

有时 JDBC 不支持以下方法会出现 `TYPE_FORWARD_ONLY' 之类的错误,请使用此解决方案

Sqlite 在 JDBC 中不支持。

resultSet.last();
size = resultSet.getRow();
resultSet.beforeFirst();

所以当时使用这个解决方案。

【讨论】:

谢谢,这是正确的解释和正确的解决方案。【参考方案2】:

ResultSet 具有根据提供的选项来回移动光标的方法。默认情况下,它是向前移动的(TYPE_FORWARD_ONLYResultSet 类型)。 除非 CONSTANTS 正确指示 ResultSet 的可滚动性和更新,否则您最终可能会收到错误消息。 例如。 beforeLast() 如果结果集不包含行,则此方法无效。 如果不是TYPE_FORWARD_ONLY,则抛出错误。

检查是否获取空行的最佳方法 --- 仅在检查不存在后插入新记录

if( rs.next() ) 

   Do nothing
 else 
  No records fetched!

见here

【讨论】:

【参考方案3】:

如果您有权访问导致此结果集的预准备语句,则可以使用

connection.prepareStatement(sql, 
  ResultSet.TYPE_SCROLL_INSENSITIVE, 
  ResultSet.CONCUR_READ_ONLY);

这会以您可以倒回光标的方式准备您的语句。这也记录在ResultSet Javadoc

然而,一般来说,前向和后退游标对于大型结果集可能效率很低。 SQL Server 中的另一个选项是直接在 SQL 语句中计算总行数:

SELECT my_table.*, count(*) over () total_rows
FROM my_table
WHERE ...

【讨论】:

我确实可以访问准备好的语句,但我绝不会真正胜任 SQL。当前准备好的语句如下所示:“Select m.* from [Messages] m INNER JOIN RequestMessageIndex i on m.messageGUID = i.MessageGuid where i.requestfield = 'DR' and i.indexValue like '%TAGER00%'” 所以我只需要在 SQL 语句中添加一些代码或创建另一个语句吗?抱歉,说到 SQL,我真的很笨…… @DeanGrobler:问这些问题没有错!我提到的两个选项都是有效的。在任何情况下,计算行数都会影响任何一种技术的性能。我个人更喜欢第二个,使用计算的count(*) over (partition by 1) 字段,但前提是您可以将该计数用于GUI 中的分页等操作。如果这只是关于日志记录,那么我不确定通常获取行数是否是一个好主意...... 这是 deff 获取结果集的行数所必需的,该变量将用于围绕返回的 GUI 数据构建动态表,因此 deff 必须这样做。从好的方面来说,返回的数据来自搜索功能。所以结果集的行最多只有 15 行。 @JerylCook:有一个预先存在的ResultSet,他们想要计算该结果集中的行数。我错过了什么? "接收一个 ResultSet 作为参数并返回一个包含 ResultSet 行数的 int"。我的回答显示了他们的错误(未指定ResultSet.TYPE_SCROLL_INSENSITIVE)并显示了替代方案。那么,你到底在批评什么?请注意,还有其他答案建议 SELECT count(*) 查询... @JerylCook: 干杯:-)【参考方案4】:

以下两个选项对我有用:

1) 返回 ResultSet 中行数的函数。

private int resultSetCount(ResultSet resultSet) throws SQLException
    try
        int i = 0;
        while (resultSet.next()) 
            i++;
        
        return i;
     catch (Exception e)
       System.out.println("Error getting row count");
       e.printStackTrace();
    
    return 0;

2) 使用 COUNT 选项创建第二条 SQL 语句。

【讨论】:

【参考方案5】:

如果您有表格并将 ID 存储为主要和自动增量,那么这将起作用

获取总行数的示例代码http://www.java2s.com/Tutorial/Java/0340__Database/GettheNumberofRowsinaDatabaseTable.htm

下面是代码

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;

public class Main 
  public static void main(String[] args) throws Exception 
    Connection conn = getConnection();
    Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
        ResultSet.CONCUR_UPDATABLE);

    st.executeUpdate("create table survey (id int,name varchar(30));");
    st.executeUpdate("insert into survey (id,name ) values (1,'nameValue')");
    st.executeUpdate("insert into survey (id,name ) values (2,null)");
    st.executeUpdate("insert into survey (id,name ) values (3,'Tom')");
    st = conn.createStatement();
    ResultSet rs = st.executeQuery("SELECT * FROM survey");

    rs = st.executeQuery("SELECT COUNT(*) FROM survey");
    // get the number of rows from the result set
    rs.next();
    int rowCount = rs.getInt(1);
    System.out.println(rowCount);

    rs.close();
    st.close();
    conn.close();

  

  private static Connection getConnection() throws Exception 
    Class.forName("org.hsqldb.jdbcDriver");
    String url = "jdbc:hsqldb:mem:data/tutorial";

    return DriverManager.getConnection(url, "sa", "");
  

【讨论】:

【参考方案6】:

改为使用SELECT COUNT(*) FROM ... 查询。

【讨论】:

【参考方案7】:

这里有一些代码可以避免获取计数来实例化数组,而是使用 ArrayList 代替,并且在返回之前将 ArrayList 转换为所需的数组类型。

请注意,这里的 Supervisor 类实现 ISupervisor 接口,但在 Java 中,您不能从 object[](ArrayList 的普通 toArray() 方法返回)转换为 ISupervisor[](我认为您可以在 C# 中执行此操作) ,因此您必须遍历所有列表项并填充结果数组。

/**
 * Get Supervisors for given program id
 * @param connection
 * @param programId
 * @return ISupervisor[]
 * @throws SQLException
 */
public static ISupervisor[] getSupervisors(Connection connection, String programId)
  throws SQLException

  ArrayList supervisors = new ArrayList();

  PreparedStatement statement = connection.prepareStatement(SQL.GET_SUPERVISORS);
  try 
    statement.setString(SQL.GET_SUPERVISORS_PARAM_PROGRAMID, programId);
    ResultSet resultSet = statement.executeQuery();  

    if (resultSet != null) 
      while (resultSet.next()) 
        Supervisor s = new Supervisor();
        s.setId(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ID));
        s.setFirstName(resultSet.getString(SQL.GET_SUPERVISORS_RESULT_FIRSTNAME));
        s.setLastName(resultSet.getString(SQL.GET_SUPERVISORS_RESULT_LASTNAME));
        s.setAssignmentCount(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ASSIGNMENT_COUNT));
        s.setAssignment2Count(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ASSIGNMENT2_COUNT));
        supervisors.add(s);
      
      resultSet.close();
    
   finally 
    statement.close();
  

  int count = supervisors.size();
  ISupervisor[] result = new ISupervisor[count];
  for (int i=0; i<count; i++)
    result[i] = (ISupervisor)supervisors.get(i);
  return result;

【讨论】:

在较新版本的 Java 中,您还可以在编译器和运行时使用泛型支持,例如 ArrayList 以避免强制转换 toArray() 方法的结果(它将返回 ISupervisor[]对象[] 那么,这就是泛型的魔力) 请注意,我只是在上面的示例中将“if”更改为“while” - 当您期望结果中只有 1 行时,您可以使用“if”【参考方案8】:

我刚刚做了一个getter方法。

public int getNumberRows()
    try
       statement = connection.creatStatement();
       resultset = statement.executeQuery("your query here");
       if(resultset.last())
          return resultset.getRow();
        else 
           return 0; //just cus I like to always do some kinda else statement.
       
     catch (Exception e)
       System.out.println("Error getting row count");
       e.printStackTrace();
    
    return 0;

【讨论】:

所以您执行整个查询只是为了获得计数?更好地动态编辑 SQL 查询,使其仅返回 COUNT【参考方案9】:

其他人已经回答了如何解决您的问题,所以我不会重复已经说过的内容,但我会说:您可能应该在不知道结果集计数之前找到解决问题的方法阅读结果。

在读取结果集之前实际上需要行计数的情况很少,尤其是在 Java 这样的语言中。我认为需要行计数的唯一情况是行计数是您需要的唯一数据(在这种情况下计数查询会更好)。否则,最好使用包装对象来表示表数据,并将这些对象存储在动态容器中,例如 ArrayList。然后,一旦结果集被迭代,您就可以获得数组列表计数。对于需要在读取结果集之前知道行数的每个解决方案,您可能会想到一个解决方案,它在读取之前不知道行数而无需付出太多努力。通过考虑在处理之前绕过需要知道行数的解决方案,您可以省去 ResultSet 滚动到结果集末尾然后又回到开头的麻烦(对于大型结果集来说,这可能是非常昂贵的操作) .

当然,我并不是说在读取结果集之前您可能需要行数。我只是说,在大多数情况下,当人们认为他们需要在阅读结果集之前对其进行计数时,他们可能不需要,因此值得花 5 分钟时间考虑是否还有其他方法。

只是想在这个话题上提供我的 2 美分。

【讨论】:

保持简短:如果想要同时获得计数和项目,最好的办法是递归地将项目添加到列表中(通过 resultSet 枚举器)然后获取计数并告诉列表给出一个数组(如果需要)【参考方案10】:

你的sql语句创建代码可能是这样的

statement = connection.createStatement();

要解决“com.microsoft.sqlserver.jdbc.SQLServerException: The requested operation is not supported on forward only result sets”异常更改上述代码

statement = connection.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE, 
    ResultSet.CONCUR_READ_ONLY);

以上修改后即可使用

int size = 0;
try 
    resultSet.last();
    size = resultSet.getRow();
    resultSet.beforeFirst();

catch(Exception ex) 
    return 0;

return size;

获取行数

【讨论】:

【参考方案11】:

来自http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/ResultSetMetaData.html

 ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
 ResultSetMetaData rsmd = rs.getMetaData();
 int numberOfColumns = rsmd.getColumnCount();

ResultSet 包含提供行数的元数据。

【讨论】:

行与列不同。元数据不包含任何与行有关的信息。除了获取数据库和表名之外,它还专门针对列。【参考方案12】:

大多数驱动程序仅支持转发结果集 - 因此不支持 last、beforeFirst 等方法。

如果您也在同一个循环中获取数据,则第一种方法是合适的 - 否则 resultSet 已经被迭代并且不能再次使用。

在大多数情况下,要求是在不获取行的情况下获取查询将返回的行数。遍历结果集以查找行数与处理数据几乎相同。最好做另一个 count(*) 查询。

【讨论】:

在某些数据库系统上,执行 select count(*) 查询可能非常慢,所以也许 TS 应该找到一种方法来完全不需要知道结果集的大小。 我很确定 SQL Server JDBC 驱动程序支持可倒带的结果集?这是正确初始化准备好的语句的问题......我同意@MarkRotteveel,发出两个查询只是为了获得行数可能是致命的。如果确实需要,您可以随时添加一个count(*) over (partition by 1) 窗口函数,即使这对于大型结果集也可能很慢......【参考方案13】:

您的函数将返回 ResultSet 的大小,但它的光标将设置在最后一条记录之后,因此如果不通过调用 beforeFirst()、first() 或 previous() 来回退它,您将无法读取其行,并且倒带方法不适用于仅向前的 ResultSet(您将得到与第二个代码片段中相同的异常)。

【讨论】:

以上是关于如何在 Java 中使用 ResultSet 获取行数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在java中获取Resultset的长度或大小[重复]

如何从子查询中获取 ResultSet 的别名?

java中如何获取ResultSet rs结果集中的条数?

java中如何获取ResultSet rs结果集中的条数?

Java如何获取ResultSet结果中的每一列的数据类型

如何从 JDBC ResultSet 中获取列数?