-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathF_CSV_TO_LIST.sql
123 lines (91 loc) · 4.39 KB
/
F_CSV_TO_LIST.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
create or replace function F_CSV_TO_LIST ( I_CSV_STRING in varchar2
, I_SEPARATOR in varchar2 := ','
, I_ENCLOSED_BY in varchar2 := null
) return T_STRING_LIST PIPELINED is
/********************************************************************************************************************
The F_CSV_TO_LIST is a "smart" string list separated by strings, optionally enclosed by string parser.
if the separator/delimiter is between enclosers, then the separator will be the part of the field.
if the encloser is not closed or not started then the encloser will be the part of the field.
Parameters:
-----------
I_CSV_STRING the ( delimited and optionally enclosed ) string to parse
I_SEPARATOR the field separator/delimiter
I_ENCLOSED_BY the optional encloser (both left and right)
Samples:
-------
select * from table( F_CSV_TO_LIST ( '1,2,3,1415', ',' ) )
select * from table( F_CSV_TO_LIST ( '"1,2","3,1415"', ',' ) )
select * from table( F_CSV_TO_LIST ( '"1,2","3,1415"', ',', '"' ) )
Results:
-------
1
2
3
1415
"1
2"
"3
1415"
1,2
3,1415
History of changes
yyyy.mm.dd | Version | Author | Changes
-----------+---------+----------------+-------------------------
2017.01.06 | 1.0 | Ferenc Toth | Created
********************************************************************************************************************/
V_INSIDE boolean := false;
V_CSV varchar2( 32000 ) := I_CSV_STRING;
V_FIELD varchar2( 32000 );
V_SEPARATOR varchar2( 300 ) := nvl( I_SEPARATOR, ',' );
begin
loop
if V_CSV is null then
PIPE ROW( V_FIELD );
exit;
end if;
if not V_INSIDE then
-- did we reach a separator outside?
if substr( V_CSV , 1 , length( V_SEPARATOR ) ) = V_SEPARATOR then
V_CSV := substr( V_CSV, length( V_SEPARATOR ) + 1 );
PIPE ROW( V_FIELD );
V_FIELD := '';
-- a new field starts with "enclosed by"
elsif substr( V_CSV, 1 , length( I_ENCLOSED_BY ) ) = I_ENCLOSED_BY then
V_CSV := substr( V_CSV, length( I_ENCLOSED_BY ) + 1 );
V_INSIDE := true;
V_FIELD := I_ENCLOSED_BY;
-- a new field starts
else
V_FIELD := substr( V_CSV, 1 , 1 );
V_CSV := substr( V_CSV, 2 );
V_INSIDE := true;
end if;
else -- inside
-- did we reach the end of field
if ( I_ENCLOSED_BY is null or substr( V_FIELD, 1, length( I_ENCLOSED_BY ) ) != I_ENCLOSED_BY )
and substr( V_CSV, 1, length( V_SEPARATOR ) ) = V_SEPARATOR then
V_CSV := substr( V_CSV, length( V_SEPARATOR ) + 1 );
PIPE ROW( V_FIELD );
V_INSIDE := false;
V_FIELD := '';
-- did we reach the end of field with an "enclosed by"
elsif substr( V_CSV , 1 , length( I_ENCLOSED_BY ) ) = I_ENCLOSED_BY and
nvl( substr( V_CSV , length( I_ENCLOSED_BY ) + 1, length( V_SEPARATOR ) ), V_SEPARATOR ) = V_SEPARATOR then
V_CSV := substr( V_CSV, length( I_ENCLOSED_BY ) + 1 );
V_FIELD := V_FIELD||I_ENCLOSED_BY;
-- if the field is really enclosed, then we remove the enclose strings
if substr( V_FIELD, 1, length( I_ENCLOSED_BY ) ) = I_ENCLOSED_BY and
substr( V_FIELD, -length( I_ENCLOSED_BY ) ) = I_ENCLOSED_BY then
V_FIELD := substr( V_FIELD, length( I_ENCLOSED_BY ) + 1, length( V_FIELD ) - 2 * length( I_ENCLOSED_BY ) );
end if;
V_INSIDE := false;
-- just add it to the field
else
V_FIELD := V_FIELD || substr( V_CSV, 1 , 1 );
V_CSV := substr( V_CSV, 2 );
end if;
end if;
end loop;
return;
end;
/