Первинне завантаження даних реєстру (initial load)
🌐 Цей документ доступний українською та англійською мовами. Використовуйте перемикач у правому верхньому куті, щоб змінити версію. |
Для первинного завантаження даних використовується БД-процедура PL/pgSQL.
Перед виконанням процедури первинного завантаження даних, переконайтеся, що виконано передумови, описані в секції Підготовка даних до міграції. |
1. Специфікація PL/pgSQL процедури для БД Платформи
CREATE OR REPLACE PROCEDURE p_load_table_from_csv(
p_table_name text
, p_file_name text
, p_table_columns text[]
, p_target_table_columns text[] DEFAULT NULL::text[]
);
- Опис параметрів:
-
-
p_table_name
- назва цільової таблиці; -
p_file_name
- повний шлях до файлу з даними для завантаження у форматі CSV; -
p_table_columns
- масив назв полів у файлі даних (перший рядок CSV-файлу); -
p_target_table_columns
- масив полів цільової таблиці (відсутній, якщо перелік полів збігається із полями в CSV-файлі).Значення елементів параметра
p_target_table_columns
може набувати різних форматів:-
<col_name>
— поле в цільовій таблиці отримує значення відповідного (за назвою) поля в CSV-файлі; -
<col_name>::<some_calculation_based_on_source_cols>
— поле отримує значення — результат виразуДетальніше — див. підрозділ Складний сценарій 1 у прикладах виклику. -
<col_name>::ref(lookup_col:<lookup_col_name>, ref_table:<ref_table_name>, ref_col:<ref_col_name>, ref_id:<ref_id_col_name>)
— для даного формату "під капотом" виконується наступний SQL-запит, що реалізовує пошукid
по таблиці довідника:SELECT <ref_id> INTO <col_name> FROM <ref_table> WHERE <ref_col> = <lookup_col>;
Такий запит застосовується у випадку, коли поле містить зовнішній ключ (англ. — foreign key) посилання на довідник, а значення для завантаження у CSV-файлі представлене не ідентифікатором, а описовим полем, проте значення цього поля мають бути унікальними.
Детальніше — див. підрозділ Cкладний сценарій 2 у прикладах виклику. -
<col_name>::ref_array(lookup_col:<lookup_col_name>, ref_table:<ref_table_name>, ref_col:<ref_col_name>, ref_id:<ref_id_col_name>, delim:<delimeter_character>)
— цей формат відмінний від попереднього лише тим, що поле<lookup_col_name>
у CSV-файлі містить масив описових значень. В результаті повертатиметься масив відповіднихid
.
-
-
2. Приклади виклику процедури
2.1. Простий сценарій
CALL p_load_table_from_csv('research',
'D:\PostgreSQL\csv\uuid\01-Typy_doslidgen_uuid.csv', array
['uuid','research_type'], array['research_type']);
2.2. Складний сценарій 1
CALL p_load_table_from_csv('koatuu','${dataLoadPath}03-KOATUU_simple.csv'
, array['code','category','name']
, array['code','category','name'
,'level1::substring(code,1,2)||''00000000'''
,'level2::substring(code,1,5)||''00000'''
,'type::CASE WHEN code ~ ''[0-9]{2}0{8}'' AND code !~ ''(80|85)0{8}'' THEN ''О''
WHEN code ~ ''[0-9]{2}2[0-9]{2}0{5}'' AND code !~ ''[0-9]{2}20{7}'' THEN ''Р''
WHEN coalesce(category, ''Р'') != ''Р''
OR code IN (SELECT DISTINCT substring(code,1,5)||''00000'' FROM koatuu_csv k2 WHERE category = ''Р'') AND category IS NULL
OR code ~ ''(80|85)0{8}'' THEN ''НП''
ELSE NULL END']
);
2.3. Складний сценарій 2
CALL p_load_table_from_csv('staff','D:\PostgreSQL\csv\staff.csv'
,array['uuid','laboratory','staff_status','researches','full_name','hygienist_flag','full_time_flag','salary','fixed_term_contract_flag','contract_end_date','specialization_date','specialization_end_date','dismissal_flag','dismissal_date']
,array['laboratory_id::ref(lookup_col:laboratory,ref_table:laboratory,ref_col:name,ref_id:laboratory_id)'
,'staff_status_id::ref(lookup_col:staff_status,ref_table:staff_status,ref_col:name,ref_id:staff_status_id)'
,'researches::ref_array(lookup_col:researches,ref_table:research,ref_col:research_type,ref_id:research_id,delim:#)'
,'full_name','hygienist_flag','full_time_flag','salary','fixed_term_contract_flag','contract_end_date','specialization_date','specialization_end_date','dismissal_flag','dismissal_date']
);
3. Завантаження даних до БД
Для завантаження даних в БД використовуємо стандартну функціональність liquibase.
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.2.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext xsd/dbchangelog-ext.xsd">
<property name="dataLoadPath" value="D:\PostgreSQL\csv\"/>
<changeSet author="registry owner" id="load data to dictionaries">
<sql dbms="postgresql" endDelimiter=";" splitStatements="true" stripComments="true">
CALL p_load_table_from_csv('research','${dataLoadPath}01-Typy doslidgen.csv', array['code','research_type'], array['research_type']);
CALL p_load_table_from_csv('refusal_reason','${dataLoadPath}02-Prichiny vidmov.csv', array['code','document_type','name','constant_code'], array['document_type','name','constant_code']);
CALL p_load_table_from_csv('kopfg','${dataLoadPath}05-kopfg.csv', array['code','name']);
CALL p_load_table_from_csv('solution_type','${dataLoadPath}06-Typy rishen.csv', array['id','name','constant_code'], array['name','constant_code']);
CALL p_load_table_from_csv('factor','${dataLoadPath}14-Himichni_factory_OBRV.csv', array['code','name','col3','col4'], array['name','factor_type::''Хімічний: ОБРВ''']);
CALL p_load_table_from_csv('factor','${dataLoadPath}15-Himichni factory dovilni.csv', array['code','name'], array['name','factor_type::''Хімічний: довільні''']);
</sql>
</changeSet>
</databaseChangeLog>
За детальною інформацією щодо створення фізичної моделі даних реєстру за допомогою інструмента Liquibase зверніться до розділу "Створення фізичної моделі даних реєстру" цього документа. |
4. Вимоги до файлів для завантаження до БД
Файли, що використовуватимуться для завантаження даних до БД, повинні мати чітку структуру.
- Вимоги до файлів для автоматичного завантаження в БД:
-
-
тільки СSV-формат;
-
назва файлу — латиницею;
-
кодування —
UTF8
; -
перший рядок містить назви полів;
-
починаючи із другого рядка містяться значення полів (структура відповідає назвам полів із першого рядка);
-
значення полів одного рядка файлу повністю визначають значення полів, необхідних для створення запису в базі даних;
-
розділювач значень полів:
,
(кома) або;
(крапка з комою); -
відсутність значення (
NULL
) передається відсутнім значенням, наприклад,…значення 1,,значення 3…
, тобто відсутнє значення пропускається між двома комами, а не позначається пробілом); -
наявність унікальності за одним бізнес-полем (наприклад, поле
Назва
) — для довідників; -
для позначення масивів описових значень використовуються фігурні дужки
{
,}
.
-
5. Рекомендації для завантаження великої кількості даних
Для завантаження великих csv-файлів (десятки і сотні мегабайт) можна використати стандартний SQL код замість процедури. Для коректної роботи реєстру такий SQL код повинен також створити історичні дані (таблиця _hst
) та заповнити поля з метаданими (колонки ddm_
), тобто повторити ті операції що процедура виконує автоматично. В прикладі наведений коректний та найбільш ефективний метод це зробити.
-- Створення тимчасової проміжної таблиці, яка
-- відповідає формату csv файлу що завантажується
CREATE TABLE account_csv_stage (username text, bank_number text);
-- Завантаження даних із csv файлу в проміжну таблицю
COPY account_csv_stage (username,bank_number)
FROM '${dataLoadPath}account.csv'
WITH (HEADER, FORMAT CSV);
-- Вставка даних в основну та історичну таблиці
WITH main_table_cte AS (
INSERT INTO account (
username
, bank_number
, ddm_created_by
, ddm_updated_by
)
SELECT username
, bank_number
, 'admin'
, 'admin'
FROM account_csv_stage
RETURNING *)
INSERT INTO account_hst (
id
, username
, bank_number
, ddm_created_by
, ddm_created_at
, ddm_dml_op
, ddm_system_id
, ddm_application_id
, ddm_business_process_id)
SELECT id
, username
, bank_number
, ddm_created_by
, CURRENT_TIMESTAMP
, 'I' as ddm_dml_op
, (SELECT ss.system_id
FROM ddm_source_system ss
WHERE ss.system_name ='initial load') ddm_system_id
, (SELECT sa.application_id
FROM ddm_source_application sa
WHERE sa.application_name ='initial load') ddm_application_id
, (SELECT sb.business_process_id
FROM ddm_source_business_process sb
WHERE sb.business_process_name ='initial load process') ddm_business_process_id
FROM main_table_cte;
-- Видалення тимчасової проміжної таблиці
DROP TABLE account_csv_stage;
Таким кодом можна замінити виклик процедури в XML-шаблоні для завантаження даних. Для кожного завантаження файлу таким методом, варто створювати окремий ченджсет.