Теперь люди любят бесконечно препираться о том, является ли «пройти по ссылке» правильным способом описать, что такое Java et al. действительно делаю. Дело в том, что:
- Передача объекта не копирует объект.
- Объект, переданный функции, может иметь свои члены, модифицированные функцией.
- Первичное значение, переданное функции, не может быть изменено функцией. Копия сделана.
В моей книге это называется передачей по ссылке.
- Брайан Би - Какие языки программирования проходят по ссылке?
Следующие работы ссылаются на него как на выбор * из таблицы (разделитель ('a, b, c, d'))
create or replace function splitter(p_str in varchar2) return sys.odcivarchar2list
is
v_tab sys.odcivarchar2list:=new sys.odcivarchar2list();
begin
with cte as (select level ind from dual
connect by
level <=regexp_count(p_str,',') +1
)
select regexp_substr(p_str,'[^,]+',1,ind)
bulk collect into v_tab
from cte;
return v_tab;
end;
/
Увы, в 11g нам все равно придется использовать наши собственные токенизаторы PL / SQL, используя типы SQL. В 11gR2 Oracle предоставила нам агрегирующую функцию для объединения результатов в строку CSV, поэтому, возможно, в 12i они предоставят обратную возможность.
Если вы не хотите создавать тип SQL, вы можете использовать встроенный SYS.DBMS_DEBUG_VC2COLL, например:
create or replace function string_tokenizer
(p_string in varchar2
, p_separator in varchar2 := ',')
return sys.dbms_debug_vc2coll
is
return_value SYS.DBMS_DEBUG_VC2COLL;
pattern varchar2(250);
begin
pattern := '[^('''||p_separator||''')]+' ;
select trim(regexp_substr (p_string, pattern, 1, level)) token
bulk collect into return_value
from dual
where regexp_substr (p_string, pattern, 1, level) is not null
connect by regexp_instr (p_string, pattern, 1, level) > 0;
return return_value;
end string_tokenizer;
/
Здесь он находится в действии:
SQL> select * from table (string_tokenizer('one, two, three'))
2 /
COLUMN_VALUE
----------------------------------------------------------------
one
two
three
SQL>
Подтверждение: этот код является вариантом кода I найденный в блоге Tanel Poder .
Для оптимальной производительности лучше избегать использования иерархических запросов (CONNECT BY) в функции сплиттера.
Следующая функция сплиттера значительно улучшает работу с большими объемами данных
CREATE OR REPLACE FUNCTION row2col(p_clob_text IN VARCHAR2)
RETURN sys.dbms_debug_vc2coll PIPELINED
IS
next_new_line_indx PLS_INTEGER;
remaining_text VARCHAR2(20000);
next_piece_for_piping VARCHAR2(20000);
BEGIN
remaining_text := p_clob_text;
LOOP
next_new_line_indx := instr(remaining_text, ',');
next_piece_for_piping :=
CASE
WHEN next_new_line_indx <> 0 THEN
TRIM(SUBSTR(remaining_text, 1, next_new_line_indx-1))
ELSE
TRIM(SUBSTR(remaining_text, 1))
END;
remaining_text := SUBSTR(remaining_text, next_new_line_indx+1 );
PIPE ROW(next_piece_for_piping);
EXIT WHEN next_new_line_indx = 0 OR remaining_text IS NULL;
END LOOP;
RETURN;
END row2col;
/
Эта разница в производительности может наблюдаться ниже (я использовал сплиттер функции, как было указано ранее в этом обсуждении).
SQL> SET TIMING ON
SQL>
SQL> WITH SRC AS (
2 SELECT rownum||',a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'||rownum txt
3 FROM DUAL
4 CONNECT BY LEVEL <=10000
5 )
6 SELECT NULL
7 FROM SRC, TABLE(SYSTEM.row2col(txt)) t
8 HAVING MAX(t.column_value) > 'zzz'
9 ;
no rows selected
Elapsed: 00:00:00.93
SQL>
SQL> WITH SRC AS (
2 SELECT rownum||',a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'||rownum txt
3 FROM DUAL
4 CONNECT BY LEVEL <=10000
5 )
6 SELECT NULL
7 FROM SRC, TABLE(splitter(txt)) t
8 HAVING MAX(t.column_value) > 'zzz'
9 ;
no rows selected
Elapsed: 00:00:14.90
SQL>
SQL> SET TIMING OFF
SQL>
У меня не установлен 11g, но есть операция PIVOT и UNPIVOT для преобразования столбцов в строки / строки в столбцы, что может быть хорошей отправной точкой.
http://www.oracle.com/technology/pub/articles/oracle-database-11g-top-features/11g-pivot.html
(Фактически проведенное некоторое дальнейшее исследование, это не подходит для этого случая - оно работает с фактическими строками / столбцами, но не с наборами данных в столбце).
Существует также DBMS_UTILITY.comma_to_table и table_to_comma для преобразования списков CSV в pl / sql-таблицы. Есть некоторые ограничения (обработка строк и т. Д.), Но может быть хорошей отправной точкой.
Моей наклонностью было бы использовать подход TYPE с простой функцией, которая выполняет comma_to_table, затем PIPE ROW для каждой записи в результат comma_to_table (к сожалению, DBMS_UTILITY.comma_to_table - это процедура, поэтому нельзя звонить из SQL).
Вот еще одно решение, использующее регулярное выражение, полностью в sql.
SELECT regexp_substr('one,two,three','[^,]+', 1, level) abc
FROM dual
CONNECT BY regexp_substr('one,two,three', '[^,]+', 1, level) IS NOT NULL