【问题标题】:How to check if resultset has one row or more?如何检查结果集是否有一行或更多?
【发布时间】:2011-02-05 05:04:01
【问题描述】:

如何使用 JDBC 检查结果集是否有一行或多行?

【问题讨论】:

  • 这确实是 JDBC 中缺少的东西,原因是并非所有数据库系统都支持提前获取结果集的大小(因为结果不是预取的)。不幸的是,这意味着您无法在支持它的数据库(例如 MySQL)中轻松使用这些功能。

标签: java sql jdbc resultset


【解决方案1】:

我的明智建议:获取第一个结果行,然后尝试获取下一个结果行。如果尝试成功,则您有不止一行。

如果有不止一行,并且您想要处理该数据,则需要缓存第一行中的内容,或者使用可滚动的结果集,以便您可以在通过结果。

您还可以通过在查询的其余部分执行SELECT COUNT(*) 来直接向 SQL 询问此信息;结果将是 0、1 或更多,具体取决于查询的其余部分将返回多少行。这很容易实现,但需要对数据库进行两次查询,假设您接下来要读取和处理实际查询。

【讨论】:

    【解决方案2】:
    ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
    boolean isMoreThanOneRow = rs.first() && rs.next();
    

    你没有问这个,但你可能需要它:

    boolean isEmpty = ! rs.first();
    

    通常,我们不需要行数,因为我们使用 WHILE 循环而不是 FOR 循环来迭代结果集:

    ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
    while (rs.next()) {
        // retrieve and print the values for the current row
        int i = rs.getInt("a");
        String s = rs.getString("b");
        float f = rs.getFloat("c");
        System.out.println("ROW = " + i + " " + s + " " + f);
    }
    

    但是,在某些情况下,您可能希望将结果窗口化,并且您需要提前将记录计数显示给用户,例如 Row 1 to 10 of 100。您可以先使用SELECT COUNT(*) 进行单独查询,以获取记录计数,但请注意,该计数只是近似值,因为可以在执行两个查询的时间之间添加或删除行。

    来自ResultSet Overview的样本

    【讨论】:

    • isMoreThanOneRow 给我错误,请求的操作不支持只转发结果集。
    • @Vodo-SioskBaas,您需要在executeQuery 语句之后立即执行此操作,这样first() 就不需要倒带或更改您的光标,以便它可以倒带。跨度>
    【解决方案3】:

    有很多选择,由于您没有提供更多上下文,所以剩下的就是猜测。我的答案按复杂性和性能升序排序。

    1. 只需运行select count(1) FROM ... 即可获得答案。您必须运行另一个实际选择并返回数据的查询。
    2. 使用rs.next() 进行迭代并数数,直到您满意为止。然后,如果您仍然需要实际数据,请重新运行相同的查询。
    3. 如果您的驱动程序支持向后迭代,请使用rs.next() 几次,然后使用rs.previous() 倒回。

    【讨论】:

    • 如果您的驱动程序不支持向后迭代,first() 通常可以重新开始。
    【解决方案4】:

    您不需要 JDBC。通常的习惯用法是将所有结果收集到一个集合中,并利用集合方法,例如List#size()

    List<Item> items = itemDAO.list();
    
    if (items.isEmpty()) {
        // It is empty!
    if (items.size() == 1) {
        // It has only one row!
    } else {
        // It has more than one row!
    }
    

    list() 方法看起来像什么:

    public List<Item> list() throws SQLException {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        List<Item> items = new ArrayList<Item>();
    
        try {
            connection = database.getConnection();
            statement = connection.createStatement();
            resultSet = statement.executeQuery(SQL_LIST);
            while (resultSet.next()) {
                Item item = new Item();
                item.setId(resultSet.getLong("id"));
                item.setName(resultSet.getString("name"));
                // ...
                items.add(item);
            }
        } finally {
            if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {}
            if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
            if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
        }
    
        return items;
    }
    

    【讨论】:

    • 这不能很好地扩展。如果结果集有数百万行怎么办?
    • @mindas:那么SELECT * FROM table 他们已经没有意义了。那么你需要SELECT COUNT(*) FROM table。 JDBC 根本不是用于此特定目的的正确工具,这正是 JDBC 中不存在虚构的 ResultSet#size() 方法的原因。
    • 原始问题从未说过它正在做SELECT * FROM table 我也没有建议过。最初的问题并没有假设所有数据实际上也是必要的。
    • @mindas:不管怎样,仍然没有理由使用 JDBC 来做这件事。要么使用 SQL 选择行数,要么使用集合方法获取结果大小。
    【解决方案5】:

    使用ResultSetMetaData 类获取行数。

    您可以从您的代码中创建ResultSetMetaData,例如:

    ResultSetMetaData rsmd = resultSet.getMetaData();   //get ResultSetMetaData
    rsmd.getColumnCount();       // get row count from resultsetmetadata
    

    【讨论】:

    • -1 ResultSetMetaData 与行数无关。rsmd.getColumnCount() 为您提供结果集的列数
    【解决方案6】:

    如果要确保正好一行,可以确保第一行是最后一行:

    ResultSet rs = stmt.executeQuery("SELECT a FROM Table1 WHERE b=10");
    if (rs.isBeforeFirst() && rs.next() && rs.isFirst() && rs.isLast()) {
        // Logic for where there's exactly 1 row
        Long valA = rs.getLong("a");    
        // ... 
    } 
    else {  
        // More that one row or 0 rows returned.    
        // .. 
    }
    

    【讨论】:

    • 这不起作用,因为rs.next() 已经跳到下一个结果集,它会给你错误的数据。我在 join 子句上对其进行了测试,它删除了一个元素
    【解决方案7】:

    此实现允许您检查查询结果是否为空,但代价是复制了一些行。

    ResultSet result = stmt.executeQuery("SELECT * FROM Table");
    
    if(result.next()) {
       // Duplicate the code which should be pasted inside while
       System.out.println(result.getInt(1));
       System.out.println(result.getString(2));
    
       while(result.next()){
       System.out.println(result.getInt(1));
       System.out.println(result.getString(2));
       }
    }else{
    System.out.println("Query result is empty");
    }
    

    缺点:

    1. 在此实现中,部分代码将被复制。
    2. 您无法知道结果中有多少行。

    【讨论】:

      猜你喜欢
      • 2014-03-01
      • 2013-06-20
      • 2013-05-09
      • 2014-04-13
      • 1970-01-01
      • 2010-10-26
      • 2014-12-20
      相关资源
      最近更新 更多