Skip to content

Commit 067291b

Browse files
authored
Create csv_parse.sql
1 parent fbed3c9 commit 067291b

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

functions/csv_parse.sql

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
create or replace function csv_parse(
2+
data text, -- данные в формате CSV без header
3+
delimiter char(1) default ',', -- задайте символ, разделяющий столбцы в строках файла, возможные вариаты: ';', ',', E'\t' (табуляция)
4+
header boolean default true -- содержит строку заголовка с именами столбцов, игнорировать её?
5+
) returns setof text[]
6+
immutable
7+
strict
8+
parallel safe -- Postgres 10 or later
9+
language plpgsql
10+
as
11+
$func$
12+
-- https://en.wikipedia.org/wiki/comma-separated_values
13+
-- https://postgrespro.ru/docs/postgresql/13/sql-copy
14+
declare
15+
parse_pattern text default replace($$
16+
(?: ([^"<delimiter>\r\n]*) #1 value without quotes or
17+
| \x20* ("(?:[^"]+|"")*") \x20* #2 value inside quotes
18+
)
19+
(?: (<delimiter>) #3 values delimiter or
20+
| [\r\n]+ # rows delimiter
21+
)
22+
$$, '<delimiter>', replace(delimiter, E'\t', '\t'));
23+
begin
24+
return query
25+
select * from (
26+
select
27+
(select array_agg(
28+
case when length(field) > 1 and
29+
left(field, 1) = '"' and
30+
right(field, 1) = '"' then replace(substring(field, 2, length(field) - 2), '""', '"')
31+
else nullif(trim(field), '')
32+
end
33+
order by num)
34+
from unnest(string_to_array(t.row, E'\x01' || delimiter || E'\x02')) with ordinality as q(field, num)
35+
) as row
36+
from unnest(string_to_array(
37+
regexp_replace(data || E'\n', parse_pattern, E'\\1\\2\x01\\3\x02', 'gx'),
38+
E'\x01\x02'
39+
)) as t(row)
40+
) as t
41+
where row is not null and array_to_string(row, '') != ''
42+
offset header::int;
43+
end;
44+
$func$;
45+
46+
select
47+
CASE WHEN row[1] ~ '^\d+$' THEN row[1]::integer ELSE NULL END AS id,
48+
row[2] AS kladr_id,
49+
row[3] AS name
50+
from csv_parse($$
51+
id; kladr_id; name
52+
501 ; 8300000000000 ; ";Автономный ;"";округ""
53+
""Ненецкий"";";unknown
54+
751;8600800000000; " Автономный округ ""Ханты-Мансийский"", Район Советский" ;
55+
1755;8700300000000; Автономный округ Чукотский, Район Билибинский
56+
1725;7501900000000;Край Забайкальский, Район Петровск-Забайкальский
57+
58+
;;
59+
711;2302100000000;Край Краснодарский, Район Лабинский
60+
729;2401600000000;Край Красноярский, Район Иланский
61+
765;2700700000000;Край Хабаровский, Район Вяземский
62+
765;;
63+
$$, ';', false) as row;

0 commit comments

Comments
 (0)