При проверке на вхождение списка в другогой список, ошибка: PLS-00306: wrong number or types of arguments in call to SUBMULTISET
В этом вопросе показано как проверить условие, является ли список подсписком другого списка, при условии, что элементы списка - скалярные (или встроенные) типы данных.
Пробую с композитным типом данных, но получаю ошибку:
declare
type itemRec is record (id int, name varchar(8));
type itemList is table of itemRec;
childItems itemList := itemList (itemRec(1,'item1'),itemRec(2,'item2'));
parentItems itemList := itemList (itemRec(1,'item1'),itemRec(2,'item2'),itemRec(3,'item3'));
begin null;
if childItems submultiset of parentItems then null; end if;
end;
/
PLS-00306: wrong number or types of arguments in call to 'SUBMULTISET'
В документации к условию SUBMULTISET сказано, что элементы списков должны быть сравнимы:
The element types of the nested table must be comparable. Refer to Comparison Conditions for information on the comparability of nonscalar types.
И далее по ссылке:
Two objects of nonscalar type are comparable if they are of the same named type and there is a one-to-one correspondence between their elements.
Но в примере выше ведь можно сравнить, что поля id и name равны?
Почему возникает эта ошибка и как её обойти?
PS В среде СУБД вместо "список" используется термин "коллекция", но суть от этого не меняется...
Ответы (1 шт):
Переменные с типом данных - запись (RECORD) нельзя напрямую сравнить:
declare
type itemRec is record (id int, name varchar(8));
rec1 itemRec := itemRec(1,'item1');
rec2 itemRec := itemRec(1,'item1');
begin null;
if rec1 = rec2 then null; end if;
end;
/
PLS-00306: wrong number or types of arguments in call to '='
Приведённые в вопросе цитаты касаются только типов данных известных в SQL, RECORD им не является. В подглаве Record Comparisons:
Records cannot be tested natively for nullity, equality, or inequality. [...]
You must write your own functions to implement such tests.
Можно конечно написать функцию, но она будет неизвестна условию SUBMULTISET.
Поэтому, решением будет, либо писать ещё одну фунцию с поэлементным сравнением в цикле, либо, что проще, воспользоваться обьектными типами, которые хорошо интегрированы в PL/SQL. Им тоже будет нужна функция для сравнения:
nested tables of user-defined object types, even if their elements are comparable, must have MAP methods defined on them to be used in equality
Воспроизводимый пример:
create or replace type itemRec force is object (id int, name varchar(8), map member function compare return varchar2)
/
create or replace type body itemRec as
map member function compare return varchar2 is
begin return to_char(id)||name;
end;
end;
/
create or replace type itemList is table of itemRec;
/
declare
childItems itemList := itemList (itemRec(1,'item1'),itemRec(2,'item2'));
parentItems itemList := itemList (itemRec(1,'item1'),itemRec(2,'item2'),itemRec(3,'item3'));
rec1 itemRec := itemRec(1,'item1');
rec2 itemRec := itemRec(1,'item1');
begin
if childItems submultiset of parentItems then
dbms_output.put_line ('is subset');
else
dbms_output.put_line ('is not subset'); end if;
childItems.extend;
childItems(childItems.last) := itemRec(9,'item9');
if childItems submultiset of parentItems then
dbms_output.put_line ('is subset');
else
dbms_output.put_line ('is not subset'); end if;
end;
/
Результат:
is subset
is not subset