Рассмотрим эти два примера на PL/SQL:
Правило: из меню доступны только допустимые варианты.
Эти значения являются переменными, а не строками в таблице, и желаемый результат присваивается переменной. Какие инструменты я могу использовать для возврата невыбранных пунктов меню?
--Case #1
onmenu := '06,02,00,03';
choice := '06,01,00';
-- Desired Output: Because Choices 06 and 00 are not in Error.
-- Leaving 02,03 as remaining options.
'02,03'
--Case #2
onmenu := '06,02,00';
choice := '00,01,06';
-- Desired Output: Because only choice 01 is in error
-- respond with unchosen option.
'02'
Разделите строку, разделенную запятыми, на строки, поместите ее в коллекцию, используйте оператор multiset, чтобы вычесть выбор из onmenu. Вот один из вариантов:
DECLARE
TYPE t_vc_array IS TABLE OF VARCHAR2(100);
l_onmenu VARCHAR2(100);
l_choice VARCHAR2(100);
l_onmenu_a t_vc_array;
l_choice_a t_vc_array;
l_result_a t_vc_array;
FUNCTION split_to_array (l_string VARCHAR2) RETURN t_vc_array
IS
l_returnval t_vc_array;
BEGIN
l_returnval := t_vc_array();
WITH rws as (
SELECT l_string str FROM dual
)
SELECT regexp_substr (
str,
'[^,]+',
1,
LEVEL
) value
BULK COLLECT INTO l_returnval
FROM rws
CONNECT BY LEVEL <=
LENGTH ( str ) - LENGTH ( REPLACE ( str, ',' ) ) + 1;
RETURN l_returnval;
END;
BEGIN
l_onmenu := '06,02,00,03';
l_choice := '06,01,00';
l_onmenu_a := split_to_array(l_onmenu);
l_choice_a := split_to_array(l_choice);
l_result_a := l_onmenu_a MULTISET EXCEPT l_choice_a;
FOR i IN 1 .. l_result_a.COUNT LOOP
dbms_output.put_line(l_result_a(i));
END LOOP;
END;
/
02
03
PL/SQL procedure successfully completed.
Вы можете решить это в SQL, используя:
WITH bounds (onmenu, choice, spos, epos) AS (
SELECT onmenu,
choice,
1,
INSTR(onmenu, ',', 1)
FROM table_name
UNION ALL
SELECT onmenu,
choice,
epos + 1,
INSTR(onmenu, ',', epos + 1)
FROM bounds
WHERE epos > 0
)
SELECT onmenu,
choice,
LISTAGG(
CASE epos
WHEN 0
THEN SUBSTR(onmenu, spos)
ELSE SUBSTR(onmenu, spos, epos - spos)
END,
','
) WITHIN GROUP (ORDER BY ROWNUM) AS unchosen
FROM bounds
WHERE ','||choice||','
NOT LIKE
CASE epos
WHEN 0
THEN '%,' || SUBSTR(onmenu, spos) || ',%'
ELSE '%,' || SUBSTR(onmenu, spos, epos - spos) || ',%'
END
GROUP BY onmenu, choice
Что для примера данных:
CREATE TABLE table_name (onmenu, choice) AS
SELECT '06,02,00,03', '06,01,00' FROM DUAL UNION ALL
SELECT '06,02,00', '00,01,06' FROM DUAL
Выходы:
преобразуйте списки строк в фактические коллекции (массивы) и используйте SQL. А еще лучше, не позволяйте вызывающим объектам передавать такие строки с несколькими значениями.