Очень неприятно иметь неправильное измерение перед обработкой данных, но если вам нужно сохранить их в массиве, вы можете рассмотреть возможность использования структуры данных, такой как List, а затем преобразовать их в массив с помощью метода toArray ().
AndreaTaroni86
Ответы:
270
Сделайте SELECT COUNT(*) FROM ...запрос вместо этого.
ИЛИ
int size =0;if(rs !=null){
rs.last();// moves cursor to the last row
size = rs.getRow();// get row id }
В любом случае вам не придется перебирать все данные.
last () и getRow () не являются статическими методами в классе ResultSet.
JeeBee
70
Ради краткости я всегда ссылаюсь на методы таким образом, когда пишу о них другим, независимо от того, статичны они или нет. На самом деле подразумевается создание экземпляра объекта и вызов метода.
лаз
51
Я пишу SomeClass.staticMethod () и SomeClass # instanceMethod () для уменьшения путаницы.
Джейк
9
Как получить значение, возвращаемое при выполнении select count?
Нафтули Кей
16
ResultSet#last()не работает со всеми типами ResultSetобъектов, вам нужно убедиться, что вы используете тот, который либо: ResultSet.TYPE_SCROLL_INSENSITIVEлибоResultSet.TYPE_SCROLL_SENSITIVE
Marius Ion
91
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}
В блоке кода if (rs.last ()) правильным методом будет rs.beforeFirst () вместо rs.first ()? Таким образом, вы не пропускаете первую запись в наборе результатов для обработки в цикле while.
karlgrz
Вы не забыли установить курсор обратно на beforeFirst за пределами блока if?
Гоблины
Как говорят документы ResultSet , getRow()работает для TYPE_FORWARD_ONLYResultSet и beforeFirst()выдает ошибки для них. Разве этот ответ не ошибочен?
CodePro_NotYet
5
Это работает только в том случае, если инструкция создается с параметром без ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
учета
19
Хорошо, если у вас есть ResultSetтип, который ResultSet.TYPE_FORWARD_ONLYвы хотите сохранить таким образом (а не переключаться на ResultSet.TYPE_SCROLL_INSENSITIVEили ResultSet.TYPE_SCROLL_INSENSITIVEдля того, чтобы иметь возможность использовать .last()).
Я предлагаю очень хороший и эффективный хак, где вы добавляете первый поддельный / фальшивый ряд вверху, содержащий количество строк.
пример
Допустим, ваш запрос следующий
select MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR
from MYTABLE
where...blahblah...
и ваш вывод выглядит
true65537"Hey"-32768"The quick brown fox"false123456"Sup"300"The lazy dog"false-123123"Yo"0"Go ahead and jump"false3"EVH"456"Might as well jump"...[1000 total rows]
Просто рефакторинг вашего кода примерно так:
Statement s=myConnection.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);String from_where="FROM myTable WHERE ...blahblah... ";//h4xResultSet 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);
Вывод вашего запроса теперь будет что-то вроде
1000nullnullnullnullnullnulltrue65537"Hey"-32768"The quick brown fox"nullfalse123456"Sup"300"The lazy dog"nullfalse-123123"Yo"0"Go ahead and jump"nullfalse3"EVH"456"Might as well jump"...[1001 total rows]
Так что вам просто нужно
if(rs.next())System.out.println("Recordcount: "+rs.getInt("RECORDCOUNT"));//hack: first record contains the record countwhile(rs.next())//do your stuff
Интересно, но как бы вы динамически / в общем случае генерировали первые операторы select: cast (null as boolean) как MYBOOL, ect? Для этого вам понадобятся метаданные полей и типов данных оператора «select», таких как boolean, char, int, ect ...), для которых может потребоваться дополнительное отключение БД, которое сведет на нет все преимущества.
user1697575
Это полезно, когда у вас есть доступ ко всем полевым деталям, а скорость - ваша главная задача (и, следовательно, нужно придерживаться быстрого ResultSet.TYPE_FORWARD_ONLY)
Я не понимаю, в чем недостаток использования этого метода для расчета размера ResultSet. Это здорово ... не нужно использовать дополнительный параметр SQL. Пожалуйста, прокомментируйте этот метод.
Madeyedexter
5
Производительность является ключевым словом здесь. Представьте, что ваш набор результатов составляет 100 миллионов записей, и вы увидите проблему
Пьер
7
Я хочу знать размер результирующего набора ДО обработки результатов, потому что мне нужно заранее создать массив того же размера. И, как отмечено в других ответах, сканирование всех строк дважды не всегда будет работать.
Переключение с ResultSet.TYPE_FORWARD_ONLYна ResultSet.TYPE_SCROLL_INSENSITIVEобычно влечет за собой огромные потери производительности.
Унай Виви
3
Я проверил это на своей таблице (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
Вит Бернатик
4
Способ получения размера ResultSet, нет необходимости использовать ArrayList и т. Д.
int size =0;if(rs !=null){
rs.beforeFirst();
rs.last();
size = rs.getRow();}
Теперь Вы получите размер, и если вы хотите распечатать ResultSet, перед печатью используйте следующую строку кода,
Здесь предлагается много ppl, ResultSet.last()но для этого вам нужно будет открыть соединение, ResultSet.TYPE_SCROLL_INSENSITIVEкоторое для встроенной базы данных Derby в 10 раз МЕДЛЕННО, чем ResultSet.TYPE_FORWARD_ONLY.
Согласно моим микротестам для встроенных баз данных Derby и H2, звонить намного быстрее, SELECT COUNT(*)чем ваш SELECT.
ResultSet rs = job.getSearchedResult(stmt);int rsCount =0;//but notice that you'll only get correct ResultSet size after end of the while loopwhile(rs.next()){//do your other per row stuff
rsCount = rsCount +1;}//end while
Да, это работает. Но я думаю, что OP борется с тем, чтобы узнать количество строк перед тем, как их обработать. До сих пор мне приходилось бороться с этой проблемой: 1.) разбивкой на страницы строк записей 2.) отображением строк, обработанных в длительных задачах для целей мониторинга прогресса ...
ppeterka
Предварительное распределение размера структуры данных является еще одной причиной. Я видел множество библиотек, возвращающих 10 списков элементов, когда есть только одно значение, потому что у разработчиков была такая же проблема с ResultSet.
Я проверил значение времени выполнения интерфейса ResultSet и обнаружил, что это в значительной степени ResultSetImpl все время. ResultSetImpl имеет метод, getUpdateCount()который вызывает значение, которое вы ищете.
Этот пример кода должен быть достаточным: ResultSet resultSet = executeQuery(sqlQuery); double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()
Я понимаю, что уныние - это вообще небезопасная процедура, но этот метод еще не подвел меня.
Не работает с Tomcat / MySQL:java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.DelegatingResultSet cannot be cast to com.mysql.jdbc.ResultSetImpl
Panu Haaramo
1
Сегодня я использовал эту логику, почему я не знаю, получить счет RS.
int chkSize =0;if(rs.next()){do{..... blah blah
enter code here for each rs.
chkSize++;}while(rs.next());}else{
enter code here for rs size =0}// good luck to u.
theStatement=theConnection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);ResultSet theResult=theStatement.executeQuery(query);//Get the size of the data returned
theResult.last();int size = theResult.getRow()* theResult.getMetaData().getColumnCount();
theResult.beforeFirst();
Перемещает курсор в первую строку этого ResultSetобъекта.
Возвращает:
trueесли курсор находится в допустимой строке; falseесли в наборе результатов нет строк
Броски:
SQLException- если произошла ошибка доступа к базе данных; этот метод вызывается для закрытого набора результатов или тип набора результатовTYPE_FORWARD_ONLY
Самый простой подход - выполнить запрос Count (*), выполнить resultSet.next (), чтобы указать на первую строку, а затем просто выполнить resultSet.getString (1), чтобы получить счет. Код:
ResultSet rs = statement.executeQuery("Select Count(*) from your_db");if(rs.next()){int count = rs.getString(1).toInt()}
Ответы:
Сделайте
SELECT COUNT(*) FROM ...
запрос вместо этого.ИЛИ
В любом случае вам не придется перебирать все данные.
источник
select count
?ResultSet#last()
не работает со всеми типамиResultSet
объектов, вам нужно убедиться, что вы используете тот, который либо:ResultSet.TYPE_SCROLL_INSENSITIVE
либоResultSet.TYPE_SCROLL_SENSITIVE
источник
getRow()
работает дляTYPE_FORWARD_ONLY
ResultSet иbeforeFirst()
выдает ошибки для них. Разве этот ответ не ошибочен?ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
Хорошо, если у вас есть
ResultSet
тип, которыйResultSet.TYPE_FORWARD_ONLY
вы хотите сохранить таким образом (а не переключаться наResultSet.TYPE_SCROLL_INSENSITIVE
илиResultSet.TYPE_SCROLL_INSENSITIVE
для того, чтобы иметь возможность использовать.last()
).Я предлагаю очень хороший и эффективный хак, где вы добавляете первый поддельный / фальшивый ряд вверху, содержащий количество строк.
пример
Допустим, ваш запрос следующий
и ваш вывод выглядит
Просто рефакторинг вашего кода примерно так:
Вывод вашего запроса теперь будет что-то вроде
Так что вам просто нужно
источник
ResultSet.TYPE_FORWARD_ONLY
)источник
Я получил исключение при использовании
rs.last()
:
это по умолчанию, это означает
ResultSet.TYPE_FORWARD_ONLY
, что вы можете использовать толькоrs.next()
решение:
источник
ResultSet.TYPE_FORWARD_ONLY
наResultSet.TYPE_SCROLL_INSENSITIVE
обычно влечет за собой огромные потери производительности.SELECT COUNT(*) FROM default_tbl
прежде чемSELECT COUNT(*) FROM default_tbl
это заняло в целом менее 1,5 секунды. Я тестировал на встроенной базе данных дерби 10.11.1.1Способ получения размера ResultSet, нет необходимости использовать ArrayList и т. Д.
Теперь Вы получите размер, и если вы хотите распечатать ResultSet, перед печатью используйте следующую строку кода,
источник
[Скорость рассмотрения]
Здесь предлагается много ppl,
ResultSet.last()
но для этого вам нужно будет открыть соединение,ResultSet.TYPE_SCROLL_INSENSITIVE
которое для встроенной базы данных Derby в 10 раз МЕДЛЕННО, чемResultSet.TYPE_FORWARD_ONLY
.Согласно моим микротестам для встроенных баз данных Derby и H2, звонить намного быстрее,
SELECT COUNT(*)
чем ваш SELECT.Вот более подробно мой код и мои тесты
источник
Это простой способ подсчета строк.
источник
источник
Я проверил значение времени выполнения интерфейса ResultSet и обнаружил, что это в значительной степени ResultSetImpl все время. ResultSetImpl имеет метод,
getUpdateCount()
который вызывает значение, которое вы ищете.Этот пример кода должен быть достаточным:
ResultSet resultSet = executeQuery(sqlQuery);
double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()
Я понимаю, что уныние - это вообще небезопасная процедура, но этот метод еще не подвел меня.
источник
java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.DelegatingResultSet cannot be cast to com.mysql.jdbc.ResultSetImpl
Сегодня я использовал эту логику, почему я не знаю, получить счет RS.
источник
источник
У меня была такая же проблема. Использование
ResultSet.first()
таким образом сразу после исполнения решило это:Документация ( ссылка ):
источник
Самый простой подход - выполнить запрос Count (*), выполнить resultSet.next (), чтобы указать на первую строку, а затем просто выполнить resultSet.getString (1), чтобы получить счет. Код:
источник
Дайте колонке имя ..
Ссылка на этот столбец из объекта ResultSet в int и делает вашу логику оттуда ..
источник