如何在 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_ONLY
ResultSet
类型)。
除非 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我刚刚做了一个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 获取行数?的主要内容,如果未能解决你的问题,请参考以下文章