Я немного расширю ответ Лукаса, добавив немного больше информации.
Немного поиска в Интернете обнаружил код от Тома Кайта (через Джонатана Льюиса) для конвертации между базами. Есть функция to_dec
, которая будет принимать строку и преобразовывать ее в число. Я воспроизвел код ниже:
Преобразование базового числа в десятичное:
create or replace function to_dec(
p_str in varchar2,
p_from_base in number default 16) return number
is
l_num number default 0;
l_hex varchar2(16) default '0123456789ABCDEF';
begin
for i in 1 .. length(p_str) loop
l_num := l_num * p_from_base + instr(l_hex,upper(substr(p_str,i,1)))-1;
end loop;
return l_num;
end to_dec;
Преобразование десятичного числа в базовое число:
create or replace function to_base( p_dec in number, p_base in number )
return varchar2
is
l_str varchar2(255) default NULL;
l_num number default p_dec;
l_hex varchar2(16) default '0123456789ABCDEF';
begin
if ( trunc(p_dec) <> p_dec OR p_dec < 0 ) then
raise PROGRAM_ERROR;
end if;
loop
l_str := substr( l_hex, mod(l_num,p_base)+1, 1 ) || l_str;
l_num := trunc( l_num/p_base );
exit when ( l_num = 0 );
end loop;
return l_str;
end to_base;
Эта функция может быть вызвана для преобразования растрового изображения строки в число, которое затем может использоваться с bitand. Примером этого может быть:
select to_dec('101010', 2) from dual
Oracle действительно предоставляет только BITAND
(и BIT_TO_NUM
, который здесь не очень актуален) в качестве способа выполнения логических операций, но здесь требуются следующие операции (A и B), (A AND NOT B) и ( НЕ A И B). Так что нам нужна переменная для преобразования A в NOT A. Простой способ сделать это - использовать translate.
Итак ... окончательный результат:
select
length(translate(to_base(bitand(data_A, data_B),2),'10','1')) as nb_1,
length(translate(to_base(bitand(data_A, data_NOT_B),2),'10','1')) as nb_2,
length(translate(to_base(bitand(data_NOT_A, data_B),2),'10','1')) as nb_3
from (
select
to_dec(data_A,2) as data_A,
to_dec(data_b,2) as data_B,
to_dec(translate(data_A, '01', '10'),2) as data_NOT_A,
to_dec(translate(data_B, '01', '10'),2) as data_NOT_B
from (
select '101010' as data_A, '011001' as data_B from dual
)
)
Это несколько сложнее, чем я надеялся, когда начал писать этот ответ, но, похоже, оно работает.