«ORA-01858: не числовой символ был найден там, где ожидалось число» при написании запроса в классе Java - PullRequest
0 голосов
/ 17 сентября 2018

У меня есть веб-приложение, где от пользователя берут 3 входа и после нажатия кнопки поиска отображаются результаты. Три входа: идентификатор (не уникальный), начальная дата и конечная дата. Я хочу получить результаты в следующих ситуациях: если пользователь вводит

  1. только id
  2. только дата начала (регистрация в таблице БД)
  3. только дата окончания (дата окончания в таблице БД)
  4. идентификатор и дата начала
  5. когда все поля введены вместе

В моем классе StudentManager.java у меня есть строка SQL, как показано ниже;

final String SQL_STU = " select " 
                + " t.name,"
                + " t.surname, " 
                + " t.lecture," 
                + " from studenttable t " 
                + " where t.school = 'CHC' " 

                + " and t.id = case when '" + studentInfo.getID() + "'" +" is null then t.id else '" + studentInfo.getID() + "' end "

                + " and t.enrolldate >= case when '" + studentInfo.getStartDate() + "' is null then t.enrolldate else to_date('" 
                +  studentInfo.getStartDate() + "', 'DD.MM.YYYY HH24:MI:SS') end " 

                + " and t.graduationdate >= case when '" + studentInfo.getEndDate() + "' is null then t.graduationdate else to_date('" 
                +  studentInfo.getEndDate() + "', 'DD.MM.YYYY HH24:MI:SS') end " ; 

Я выполню этот запрос и получу результаты в набор результатов.

У меня есть пара проблем с этим кодом; например, когда я закомментирую эту часть:

            + " and t.enrolldate >= case when '" + studentInfo.getStartDate() + "' is null then t.enrolldate else to_date('" 
            +  studentInfo.getStartDate() + "', 'DD.MM.YYYY HH24:MI:SS') end " 

            + " and t.graduationdate >= case when '" + studentInfo.getEndDate() + "' is null then t.graduationdate else to_date('" 
            +  studentInfo.getEndDate() + "', 'DD.MM.YYYY HH24:MI:SS') end " ; 

Он работает без ошибок, но когда я даю все входные данные null (id, date1, date2), он ничего не отображает. Разве он не должен отображать все результаты, так как нет конкретного идентификатора? (Пользователь не сможет отправить 3 пустых поля, но мне любопытно, почему это не работает так, как я упоминал?)

Другое дело, когда я выполняю весь код (с частями to_date), в заголовке выдается ошибка. Но это не дает никакой ошибки, когда я выполняю так:

  final String SQL_STU = " select " 
                    + " t.name,"
                    + " t.surname, " 
                    + " t.lecture," 
                    + " from studenttable t " 
                    + " where t.school = 'CHC' " 

                    + " and t.enrolldate >= case when '" + studentInfo.getStartDate() + "' is null then t.enrolldate else to_date('" 
                    +  studentInfo.getStartDate() + "', 'DD.MM.YYYY HH24:MI:SS') end " ;

Итак, в общем, я не мог написать запрос так, как хотел. Я не настолько опытен с вопросами. Если вы знаете какой-нибудь лучший способ, вы можете также предложить это, поскольку я зашел в тупик. Я тоже что-то пробовал с NVL, но не смог заставить его работать тоже.

Примечания:

  • ID, StartDate, EndDate являются строкой типа в моем классе StudentInfo.java
  • id - тип varchar, а даты - тип даты в таблице базы данных. (PL / SQL)

1 Ответ

0 голосов
/ 17 сентября 2018

Лучший ответ на ваш вопрос - использовать подготовленное утверждение:

String sql = "SELECT t.name, t.surname, t.lecture ";
sql += "FROM studenttable t ";
sql += "WHERE t.school = 'CHC' AND " 
sql += "t.id = COALESCE(?, t.id) AND ";
sql += "t.entrolldate >= COALESCE(?, t.enrolldate) AND ";
sql += "t.graduationdate >= COALESCE(?, t.graduationdate)";

PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, studentInfo.getID());
ps.setDate(2, studentInfo.getStartDate());
ps.setDate(3, studentInfo.getEndDate());
ResultSet rs = ps.executeQuery();

while (rs.next()) {
    // process a row
}

Причина, по которой использование оператора является предпочтительным, заключается в том, что он освобождает вас от необходимости вручную упорядочивать дату Java (и другие типы).) переменные в ваш оператор Oracle SQL.Вместо этого приведенный выше код позволяет драйверу JDBC беспокоиться о том, как преобразовать переменную даты Java в правильный формат в реальном коде SQL.Кроме того, операторы позволяют вам писать SQL-запросы с минимальными конкатенациями, что уменьшает вероятность ошибок и опечаток.

Обратите внимание, что вам может потребоваться вызвать метод установки, отличный от PreparedStatement#setDate, в зависимости от того, что getStartDate()и getEndDate() методы фактически возвращаются в ваш код Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...