Почему "while (rs.next())" необходимо здесь?

Я хочу выбрать максимальный номер строки из моей базы данных "Журналы" и сохранить ее в переменной m.

Вот мой код:

ResultSet rs = stmt.executeQuery("Select max(Line) as L from logs");

while (rs.next()) {          // Why do I need this
    int m = rs.getInt("L");
    System.out.println(m);
}

Но это не работает, если я не использую while(rs.next()).


Если я правильно понимаю, rs.next() перемещает курсор в следующую строку, но здесь, в этом результате, у меня есть только одна строка.

Итак, может кто-нибудь объяснить, почему цикл необходим? Единственное, о чем я могу думать, это то, что первый указатель установлен на имя столбца, правильно?

Ответ 1

Зачем?

Курсор сначала помещается перед первым элементом. Чтобы получить доступ к первому элементу, вам нужно его продвинуть один раз.

Очевидно, это было сделано, потому что пересечение результатов с использованием цикла очень удобно, как вы видите. Из официальной документации:

Перемещает курсор вперед на одну строку из текущей позиции. Курсор ResultSet изначально позиционируется перед первой строкой; первый вызов метода next делает первую строку текущей строкой; второй вызов делает вторую строку текущей строкой и так далее.


Решение

Поэтому, когда вам не нужен какой-либо цикл, вам нужно заранее направить курсор. Один rs.next(); технически было бы достаточно:

rs.next();
// Access the result

Однако вы, вероятно, захотите учитывать случай, когда совпадения нет, поскольку:

Когда вызов next метода возвращает false, курсор позиционируется после последней строки. Любой вызов метода ResultSet который требует текущей строки, приведет к SQLException.

Таким образом, в этом случае код будет терпеть неудачу.

Из-за этого вы должны учитывать этот случай и использовать возвращаемое boolean для защиты вашего доступа:

if (rs.next()) {
    // Access result ...
} else {
    // No match ...
}

Ответ 2

Из официальной документации (которую вы должны прочитать кстати):

Первоначально курсор позиционируется перед первой строкой. Следующий метод перемещает курсор в следующую строку, и поскольку он возвращает false, когда в объекте ResultSet больше нет строк, его можно использовать в цикле while для итерации по набору результатов.

Вам в основном нужно переместить его, в вашем случае переместить его один раз достаточно:

 rs.next(); 
 System.out.println(rs.getInt("L")); 

Ответ 3

Вы можете преобразовать это, чтобы вместо этого использовать простой оператор if.

if(rs.next()) {
    // other code here
}

Вы будете использовать while когда у вас есть несколько строк для возврата.

Ответ 4

Курсор ResultSet изначально позиционируется перед первой строкой, первый вызов метода next делает первую строку текущей строкой, второй - второй строкой текущей строки и т.д.

подумайте, что у вас есть что-то вроде этого.

->1->2->3
^

ваши "rs" первоначально указываются до 1, когда вы вызываете rs.next(), он увеличивает стрелку до 1

  ->1->2->3
    ^

поэтому, если вы не вызываете метод next(), вы не получите результат.

Надеюсь это поможет

Ответ 5

Существуют различные типы выполнения команд. Курсоры используются для чтения данных из выполненных запросов. Когда вы выполняете чтение, вы используете Forward Only Cursor по умолчанию, поэтому вы получаете следующий результат после вызова Recorset.Next()! Я не хочу углубляться здесь. Вы можете прочитать о курсорах здесь: https://docs.microsoft.com/en-us/sql/ado/guide/data/types-of-cursors-ado?view=sql-server-2017

Лучшее решение в вашем случае - использовать Scalar Resultset, который будет возвращать только ONE CELL, что именно то, что вы хотите реализовать, без необходимости прокручивать результирующий набор. В следующем примере показано, как вы можете реализовать такое:

using System;
using System.Data;
using System.Data.SqlClient;

class ExecuteScalar
{
  public static void Main()
  {
    SqlConnection mySqlConnection =new SqlConnection("server=(local)\\SQLEXPRESS;database=MyDatabase;Integrated Security=SSPI;");
    SqlCommand mySqlCommand = mySqlConnection.CreateCommand();
    mySqlCommand.CommandText ="SELECT COUNT(*) FROM Employee";
    mySqlConnection.Open();

    int returnValue = (int) mySqlCommand.ExecuteScalar();
    Console.WriteLine("mySqlCommand.ExecuteScalar() = " + returnValue);

    mySqlConnection.Close();
  }
}

Мы используем ExecuteScalar для возврата только ОДНОЙ ячейки. Помните, что даже если ваш запрос возвращает несколько строк/столбцов, это всегда будет возвращать ОЧЕНЬ ПЕРВАЯ КЛЕТКА.