【问题标题】:How to get row count using ResultSet in Java?如何在 Java 中使用 ResultSet 获取行数?
【发布时间】: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;您可能需要考虑使用实际的日志库来处理诸如输出方法名称等事情)

标签: java jdbc resultset


【解决方案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(您将得到与第二个代码片段中相同的异常)。

            【讨论】:

              猜你喜欢
              • 2014-10-10
              • 2023-03-05
              • 2023-03-17
              • 2012-01-07
              • 1970-01-01
              • 1970-01-01
              • 2010-09-25
              • 2018-07-19
              相关资源
              最近更新 更多