我需要将csv字符串拆分为n个部分。我有各种格式的地址,所以我将它们转换为csv字符串。我的报告需要3或4个地址行字段,因此我想将csv字符串拆分为报告所需的部分数量。
例如:
10,Dingle Apartments,MANZINI,,MANZINI,NGWANE STREET,,,Swaziland
应分为3个字段的相等部分:
1:10,Dingle Apartments,MANZINI
2:,MANZINI,NGWANE STREET
3:,,,Swaziland
我编写了以下代码,但它根本不能正常运行:
-- ============================================================================
-- This function splits a csv string into x parts and returns one of the parts.
-- Note: The smallest number of items in a part is hard coded to 2. Needs debug.
--
-- p_string - The csv string.
-- p_parts - The number of parts to split into.
-- p_part - The splitted part to return.
-- p_separator - The separator used in the csv string.
-- p_separator_out - The separator to return.
-- p_trim - Trim trailing separator. Y/N
-- ============================================================================
function get_csv_part
(
p_string in varchar2,
p_parts in number,
p_part in number,
p_separator in varchar2,
p_separator_out in varchar2,
p_trim in varchar2 default 'Y'
) return varchar2 is
l_answer varchar2(32767) := '';
l_count number := 0;
l_count2 number := 0;
l_size number;
l_pos number;
l_pos2 number;
begin
-- hr_utility.trace_on(null, 'FDL');
hr_utility.trace('p_string: ' || p_string);
l_pos := instr(p_string, p_separator);
-- Determine the number of separators.
while l_pos > 0 loop
l_count := l_count + 1;
l_pos := instr(p_string, p_separator, l_pos + 1);
end loop;
-- Get the size of a part.
if l_count <= p_parts then
l_size := 2;
else
l_size := floor(l_count / p_parts);
end if;
--if l_size = 1 then
-- l_size := 2;
--end if;
hr_utility.trace('l_size: ' || to_char(l_size));
l_pos := instr(p_string, p_separator);
if l_pos = 0 then
if p_part = 1 then
l_answer := p_string;
end if;
else
if p_part = 1 then
l_answer := substr(p_string, 1, l_pos - 1) || p_separator_out;
end if;
end if;
-- Split csv into parts.
while l_pos > 0 loop
l_count2 := l_count2 + 1;
l_pos2 := instr(p_string, p_separator, l_pos + 1);
hr_utility.trace('----------------------------------------');
hr_utility.trace('l_count: ' || to_char(l_count));
hr_utility.trace('l_count2: ' || to_char(l_count2));
hr_utility.trace('floor(l_count2 / l_size) + 1: ' || to_char(floor(l_count2 / l_size) + 1));
hr_utility.trace('l_pos: ' || to_char(l_pos));
hr_utility.trace('l_pos2: ' || to_char(l_pos2));
hr_utility.trace('l_answer: ' || l_answer);
-- If we are at a position that should go into the returned part.
if
(
l_size > 1
and floor(l_count2 / l_size) + 1 = p_part
)
or
(
l_size = 1
and l_count2 = p_part
)
or
(
p_part = p_parts
and l_size = 1
and l_count2 >= p_part
)
or
(
p_part = p_parts
and floor(l_count2 / l_size) + 1 >= p_part
) then
if l_pos2 = 0 then
if l_pos + 1 < length(p_string) then
l_answer := l_answer || substr(p_string, l_pos + 1) || p_separator_out;
end if;
elsif ((l_pos + 1) <= (l_pos2 - 1)) then
l_answer := l_answer || substr(p_string, l_pos + 1, ((l_pos2 - 1) - (l_pos + 1) + 1)) || p_separator_out;
else
l_answer := l_answer || p_separator_out;
end if;
end if;
l_pos := l_pos2;
end loop;
if p_part = p_parts then
l_pos := instr(p_string, p_separator, 1, l_count);
-- Dodge.
if instr(p_string, substr(p_string, l_pos + 1)) = 0 then
l_answer := l_answer || substr(p_string, l_pos + 1);
end if;
end if;
if p_trim = 'Y' then
-- Did not work if all separators.
-- l_answer := trim(trailing p_separator_out from l_answer);
if substr(l_answer, length(l_answer)) = p_separator_out then
l_answer := substr(l_answer, 1, length(l_answer) - 1);
end if;
end if;
return l_answer;
end get_csv_part;
有些问题是:
,,TEST,SWAZILIND,LOCATION,THING,,,,
请注意,出于某种原因,要求是将空白字段留给分隔符,以便部分可以是,
任何人都可以帮我解决这个问题,或者有没有人能够做到这一点?
答案 0 :(得分:0)
未经测试,但类似:
CREATE OR REPLACE function get_csv_part(
p_string in varchar2,
p_parts in number,
p_part in number,
p_separator in varchar2,
p_separator_out in varchar2,
p_trim in varchar2 default 'Y'
)
RETURN VARCHAR2 DETERMINISTIC
IS
p_value VARCHAR2(4000) := p_string;
p_start INTEGER;
p_end INTEGER;
p_items INTEGER;
p_sep_len CONSTANT INTEGER := LENGTH( p_separator );
BEGIN
IF p_value IS NULL THEN
RETURN NULL;
END IF;
p_items = ( LENGTH( p_value ) - LENGTH( REPLACE( p_value, p_separator ) ) ) / p_sep_len + 1;
IF p_part = 1 THEN
p_start := 1;
ELSE
p_start := INSTR( p_value, p_separator, 1, ROUND( ( p_part - 1 ) / p_parts * p_items ) ) + p_sep_len;
END IF;
p_end := INSTR( p_value, p_separator, 1, ROUND( p_part / p_parts * p_items ) ) - 1;
IF p_end = -1 THEN
p_value := SUBSTR( p_value, p_start );
ELSE
p_value := SUBSTR( p_value, p_start, p_end - p_start + 1 );
END IF;
IF p_trim = 'Y' THEN
WHILE SUBSTR( p_value, -p_sep_len ) = p_separator THEN
p_value := SUBSTR( p_value, 1, LENGTH( p_value ) - p_sep_len );
END LOOP;
END IF;
RETURN REPLACE( p_value, p_separator, p_separator_out );
END;
/