Oracle10 и JDBC: как заставить CHAR игнорировать конечные пробелы при сравнении?

У меня есть запрос, который имеет

... ГДЕ PRT_STATUS='ONT' ...

Однако поле prt_status определено как CHAR(5). Поэтому он всегда заполняется пробелами. В результате запрос ничего не соответствует. Чтобы этот запрос работал, я должен сделать

... ГДЕ rtrim(PRT_STATUS)='ONT'

что работает.

Это раздражает.

В то же время у пары чисто Java-клиентов СУБД (Oracle SQLDeveloper и AquaStudio) у меня НЕ возникает проблемы с первым запросом, они возвращают правильный результат. У TOAD тоже нет проблем.

Я предполагаю, что они просто переводят соединение в некоторый режим совместимости (например, ANSI), поэтому Oracle знает, что CHAR(5) должен сравниваться без учета завершающих символов.

Как я могу сделать это с объектами Connection, которые я получаю в своем приложении?

ОБНОВЛЕНИЕ Я не могу изменить схему базы данных.

РЕШЕНИЕ Именно так Oracle сравнивает поля с переданными параметрами.

Когда привязка завершена, строка передается через PreparedStatement.setString(), который устанавливает тип в VARCHAR, и, таким образом, Oracle использует сравнение без дополнений - и терпит неудачу.

Я пытался использовать setObject(n,str,Types.CHAR). Не удается. Декомпиляция показывает, что Oracle игнорирует CHAR и снова передает его как VARCHAR.

Вариант, который наконец работает,

setObject(n,str,OracleTypes.FIXED_CHAR);

Однако это делает код не переносимым.

Клиенты пользовательского интерфейса преуспевают по другой причине — они используют символьные литералы, а не привязку. Когда я набираю PRT_STATUS='ONT', 'ONT' является литералом, и поэтому сравнивается с использованием дополнения.


person Vladimir Dyuzhev    schedule 02.03.2009    source источник


Ответы (4)


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

Из правил сравнения типов данных,

Oracle использует семантику сравнения с заполнением пробелами только тогда, когда оба значения в сравнении являются выражениями типа данных CHAR, NCHAR, текстовыми литералами или значениями, возвращаемыми функцией USER.

В вашем примере 'ONT' передается как параметр привязки или он встроен в запрос в текстовом виде, как вы проиллюстрировали? Если параметр связывания, убедитесь, что он связан как тип CHAR. В противном случае проверьте используемую версию клиентской библиотеки, так как действительно старые версии Oracle (например, v6) будут иметь другую семантику сравнения для CHAR.

person vladr    schedule 02.03.2009
comment
Хм... в этом есть смысл. JDBC setString использует VARCHAR для привязки строкового параметра. Не уверен, что смогу использовать это для решения проблемы, но, по крайней мере, теперь становится яснее. - person Vladimir Dyuzhev; 02.03.2009
comment
Вероятно, вы правы: Oracle использует семантику сравнения без дополнений всякий раз, когда одно или оба значения в сравнении имеют тип данных VARCHAR2 или NVARCHAR2. Мне нужно сделать тест, чтобы проверить это. - person Vladimir Dyuzhev; 02.03.2009
comment
Спасибо, Влад! Смотрите мое решение выше. - person Vladimir Dyuzhev; 02.03.2009
comment
Рад, что проблема устранена! В. - person vladr; 03.03.2009

Если вы не можете изменить таблицу базы данных, вы можете изменить свой запрос.

Некоторые альтернативы RTRIM:

.. ГДЕ PRT_STATUS как 'ONT%'...

.. WHERE PRT_STATUS = 'ONT' ... -- 2 пробела после T

.. ГДЕ PRT_STATUS = rpad('ONT',5,' ') ...

person Edwin    schedule 02.03.2009

Я бы изменил столбец CHAR (5) на varchar2 (5) в БД.

person tuinstoel    schedule 02.03.2009
comment
Вне вопроса. БД не принадлежит к нашей группе. - person Vladimir Dyuzhev; 02.03.2009

Вы можете использовать операцию приведения к символу в своем запросе:

... WHERE PRT_STATUS=cast('ONT' as char(5))

Или более общим способом JDBC:

... WHERE PRT_STATUS=cast(? as char(5))

И затем в вашем коде JDBC используйте statement.setString(1, "ONT");

person user1697575    schedule 24.11.2017