Типы данных Oracle JDBC и Oracle CHAR

У меня есть сложная проблема с обработкой драйверов Oracle JDBC для типов данных CHAR . Возьмем эту простую таблицу:

 create table x (c char(4)); insert into x (c) values ('a'); -- inserts 'a ' 

Поэтому, когда я вставляю что-то в CHAR(4) , строка всегда заполняется пробелами. Это также выполняется, когда я выполняю запросы следующим образом:

 select * from x where c = 'a'; -- selects 1 record select * from x where c = 'a '; -- selects 1 record select * from x where c = 'a '; -- selects 1 record 

Здесь константа 'a' заполняется пробелами. Вот почему запись всегда возвращается. Это выполняется, когда эти запросы выполняются с использованием JDBC PreparedStatement . Теперь сложнее всего, когда я хочу использовать переменную bind:

 PreparedStatement stmt = conn.prepareStatement("select * from x where c = ?"); stmt.setString(1, "a"); // This won't return any records stmt.setString(1, "a "); // This will return a record stmt.executeQuery(); 

Это обходное решение:

 PreparedStatement stmt = conn.prepareStatement("select * from x where trim(c) = trim(?)"); stmt.setString(1, "a"); // This will return a record stmt.setString(1, "a "); // This will return a record stmt.executeQuery(); 

EDIT : Теперь это ограничения:

  • Вышеупомянутое обходное решение нежелательно, так как оно изменяет как содержимое c и ? , И это делает использование индексов на c довольно сложно.
  • Перемещение столбца из CHAR в VARCHAR (что должно быть, конечно) невозможно

EDIT : Причины этих ограничений связаны с тем, что я задаю этот вопрос с точки зрения разработчика jOOQ , библиотеки абстракции базы данных. Поэтому мои требования – предоставить очень общее решение, которое не нарушает ничего в клиентском коде jOOQ. Вот почему я не очень большой поклонник обходного пути. И поэтому у меня нет доступа к объявлению столбца CHAR . Но все же, я хочу иметь возможность справиться с этим делом.

Что бы вы сделали вместо этого? Какая хорошая практика для обработки типов данных CHAR когда я хочу игнорировать конечные пробелы?

Если ты хочешь

 stmt.setString(1, "a"); // This won't return any records 

для возврата записи, попробуйте

 conn.prepareStatement("select * from x where c = cast(? as char(4))") 

Я не вижу причин использовать CHAR-тип данных, даже если это char (1) в Oracle. Можете ли вы изменить тип данных вместо этого?

Решение Гэри работает хорошо. Вот альтернатива.

Если вы используете драйвер JDBC Oracle, вызов prepareStatement() фактически вернет OraclePreparedStatement , который имеет метод setFixedCHAR() который автоматически вводит ваши входы с пробелами.

 String sql = "select * from x where c = ?"; OraclePreparedStatement stmt = (OraclePreparedStatement) conn.prepareStatement(sql); stmt.setFixedCHAR(1, "a"); ... 

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

Единственная причина, по которой я бы предположил, что вы используете это по ответам Гэри, состоит в том, что вы можете resizeы столбцов, не изменяя свой код JDBC. Драйвер набирает правильное количество пробелов без участия разработчика, который должен знать / управлять размером столбца.

У меня есть хорошее решение для этого. Вы должны добавить одно свойство при получении соединения из базы данных.

 NLS_LANG=american_america.AL32UTF8 

или в Java-соединении вы можете использовать код ниже:

 java.util.Properties info = new java.util.Properties(); info.put ("user", user); info.put ("password",password); info.put("fixedString","TRUE"); info.put("NLS_LANG","american_america.AL32UTF8"); info.put("SetBigStringTryClob","TRUE"); String url="jdbc:oracle:thin:@"+serverName; log.debug("url="+url); log.debug("info="+info); Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection(url,info); 
Давайте будем гением компьютера.