Номер Oracle и соединение varchar

У меня есть запрос, который объединяет две таблицы. В одной таблице есть столбец типа varchar, а в другой таблице — числовой тип. Я выполнил свой запрос к трем базам данных оракула и вижу некоторые странные результаты, которые, надеюсь, можно объяснить. В двух базах данных работает что-то вроде следующего.

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=a.col1;

В этом запросе tableA.col1 имеет тип number, а tableB.col2 — тип varchar. Это отлично работает в двух базах данных, но не в третьей. В третьем получаю ошибку (ORA-01722). В третьем мне нужно сделать что-то вроде...

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=to_char(a.col1);

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

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


person broschb    schedule 24.02.2010    source источник
comment
Сопоставление было бы моим первым предположением. Oracle обычно разрешает неявное преобразование, поэтому может случиться так, что один столбец не проходит неявное преобразование...   -  person OMG Ponies    schedule 25.02.2010
comment
Вы написали все эти слова и так и не смогли точно объяснить, почему первый запрос не работает в третьей базе данных.   -  person APC    schedule 25.02.2010
comment
Извините, я получаю ошибку ORA-01722 в первом запросе, третья база данных   -  person broschb    schedule 25.02.2010


Ответы (1)


Одна из причин, по которой неявные преобразования терпят неудачу, заключается в том, что присоединяемый столбец varchar содержит данные, которые не являются числовыми. Oracle обрабатывает число для объединения varchar2 путем преобразования строк (см. цитату Гэри в его комментарии), поэтому он фактически выполняет это:

select a.col1, b.somecol 
from tableA a inner join tableB b on to_number(b.col2)=a.col1;

Если tableB.col2 содержит значения, которые не являются числовыми — вполне вероятно, что это строка, — тогда будет выброшено ORA-01722: invalid number. Явно приводя числовой столбец к строке, вы сокращаете поведение Oracle по умолчанию.

Тот факт, что вы не столкнетесь с этой проблемой в первых двух средах, зависит от удачи, а не от конфигурации. Он может сработать в любой момент, потому что для прерывания запроса требуется только одна нечисловая строка. Так что на самом деле вы должны работать с явным преобразованием во всех средах.

Что касается производительности, вы можете построить индекс на основе функций...

create index whatever_idx on tableA ( to_char(col1) )
/ 
person APC    schedule 24.02.2010
comment
Немного позже download.oracle.com /docs/cd/B19306_01/server.102/b14200/ При сравнении символьного значения с числовым значением Oracle преобразует символьные данные в числовое значение. - person Gary Myers; 25.02.2010
comment
Вместо этого вы можете преобразовать число в таблице A в строку, чтобы не получать ошибок, если в таблице B есть нечисловая строка. т.е. CAST(a.col1 AS VARCHAR(20)) - person Ginja Ninja; 11.09.2013