Тип данных Oracle JDBC и Oracle CHAR - PullRequest
14 голосов
/ 17 марта 2011

У меня сложная проблема с обработкой драйвером 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. Сложнее всего, когда я хочу использовать переменную связывания:

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();

РЕДАКТИРОВАТЬ : Теперь вот ограничения:

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

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

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

Ответы [ 5 ]

11 голосов
/ 17 марта 2011

Если вы хотите, чтобы

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

вернул запись, попробуйте

conn.prepareStatement("select * from x where c = cast(? as char(4))")
2 голосов
/ 17 марта 2011

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

1 голос
/ 18 ноября 2015

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

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

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

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

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

0 голосов
/ 02 ноября 2018

другой способ изменить ваш sql как

select * from x where NVL(TRIM(c),' ') = NVL(TRIM('a'),' ')
0 голосов
/ 05 марта 2018

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

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);
...