I don’t know an existing utility package for handling csv. But I can share an example code with you that makes things easier:
Function Import_Csv(msg_ IN CLOB) RETURN CLOB
IS
from_ INTEGER;
to_ INTEGER;
TYPE t_text IS TABLE OF VARCHAR2(32000) INDEX BY BINARY_INTEGER;
details_ t_text;
lines_ VARCHAR2(32000);
CURSOR get_detail IS
SELECT REGEXP_SUBSTR(lines_, '(.*?)(;|$)', 1, LEVEL, NULL, 1)
FROM dual
CONNECT BY LEVEL <= REGEXP_COUNT(lines_, ';') + 1;
BEGIN
from_ := 1;
WHILE from_ < LENGTH(msg_) LOOP
to_ := INSTR(msg_, chr(10), from_);
IF to_ > 0 THEN
lines_ := SUBSTR(msg_, from_, to_ - from_ - 1);
from_ := to_ + 1;
ELSE
lines_ := SUBSTR(msg_, from_);
from_ := LENGTH(msg_);
END IF;
lines_ := REPLACE(lines_, '''', '');
OPEN get_detail;
FETCH get_detail BULK COLLECT INTO details_;
CLOSE get_detail;
--now you can easily access the columns. e. g. details_(3) holds the third column.
END LOOP;
RETURN NULL;
END Import_Csv;