|
| 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