У меня есть две таблицы, и я заполняю их некоторыми данными:

create table qz_products (
   id    integer primary key
 , name  varchar2(20) not null unique
);

create table qz_wishlist (
   user_name   varchar2(10) not null
 , id_or_name  varchar2(20) not null
);

insert into qz_products values (1042, 'Bowling ball' );
insert into qz_products values (1088, 'Bottle opener');
insert into qz_products values (2021, 'Bikini top'   );
insert into qz_products values (2069, 'Beach parasol');

insert into qz_wishlist values ('Bob'  ,'1042');
insert into qz_wishlist values ('Bob'  ,'Bottle opener');
insert into qz_wishlist values ('Betty','Bikini top');
insert into qz_wishlist values ('Betty','2069');

Я хочу присоединиться к этим таблицам при определенном условии: когда поле id_or_name является числовым типом данных, я хотел бы присоединиться к полю id из таблицы qz_products. В противном случае я хотел бы присоединиться, используя поле имени из таблицы qz_products, поэтому результат должен быть следующим:

USER_NAME          ID NAME
---------- ---------- --------------------
Betty            2021 Bikini top
Betty            2069 Beach parasol
Bob              1042 Bowling ball
Bob              1088 Bottle opener

Мне в голову пришла идея использовать функцию VALIDATE_CONVERSION. Это мой запрос:

select w.user_name, p.id, p.name
from qz_wishlist w inner join qz_products p
on w.id_or_name = (case when validate_conversion(w.id_or_name as number) = 1 then p.id
                    else p.name end);

И у меня там ошибка:

ORA-00932: inconsistent datatypes: expected NUMBER got CHAR

Я знаю, что означает эта ошибка, но не уверен, почему она у меня. Что я там пропустил?
С наилучшими пожеланиями.

2
ElKamilaszczy 19 Дек 2019 в 13:28
Различные значения результата выражения case должны иметь совместимые типы данных. Число и символ - нет.
 – 
jarlh
19 Дек 2019 в 13:31
1
then cast(p.id as char(11))...
 – 
jarlh
19 Дек 2019 в 13:32
Блин, ты прав. Я такой глупый. Это очевидно, но я все же забыл об этом. Спасибо :)
 – 
ElKamilaszczy
19 Дек 2019 в 13:43

2 ответа

Все ветви case должны возвращать один и тот же тип данных, поэтому ваш подход не будет работать: вместо этого используйте условия or.

Кроме того, я бы рекомендовал использовать to_number() с параметром on conversion error вместо validate_conversion(). Это проверяет и конвертирует на лету. Если значение не может быть преобразовано, мы можем заставить to_number() вернуть null, поэтому оно не может совпадать с p.id.

select w.user_name, p.id, p.name
from qz_wishlist w inner join qz_products p
on 
    to_number(w.id_or_name default null on conversion error) = p.id
    or w.id_or_name = p.name

Демонстрация DB Fiddle :

USER_NAME |   ID | NAME         
:-------- | ---: | :------------
Bob       | 1042 | Bowling ball 
Bob       | 1088 | Bottle opener
Betty     | 2021 | Bikini top   
Betty     | 2069 | Beach parasol
1
GMB 19 Дек 2019 в 13:43
Спасибо, но я просто хотел знать, почему функция validate_conversion была неправильной. Однако я сделал глупую ошибку в выражении case, поэтому теперь он работает. Еще раз спасибо :)
 – 
ElKamilaszczy
19 Дек 2019 в 13:46

Спасибо @jarlh за показ проблемы. Я чувствую себя так глупо сейчас, ха-ха. Проблема была с типами данных выражения case. Тем не менее, когда я использовал

then cast(p.id as char(11))

У меня есть:

USER_NAME   ID  NAME
Bob        1088 Bottle opener
Betty      2021 Bikini top

Но это было просто - типы данных не совсем совпадали. я использовал

then cast(p.id as varchar2(11))

Который решил мою проблему. Спасибо!

1
ElKamilaszczy 19 Дек 2019 в 13:44