Предложение @LaurenzAlbe является очевидным подходом (ИМХО никогда не загружайте электронную таблицу непосредственно в свои таблицы, это ненадежные звери). Но я считаю, что ваша реализация после загрузки промежуточной таблицы ошибочна.
Во-первых, использование row_number() фактически гарантирует получение дублирующихся идентификаторов для одного и того же имени группы. Идентификаторы всегда будут увеличиваться с 1 на 1 до количества имен групп, независимо от количества ранее загруженных групп, и вы не можете гарантировать идентичную последовательность в последующих электронных таблицах. Что происходит, когда у вас есть группа, которой ранее не существовало. Кроме того, не выполняется проверка того, что имя группы еще не существует. Результат: повторяющиеся имена групп и/или несколько идентификаторов для одного и того же имени.
Во-вторых, вы пытаетесь использовать идентификатор из электронной таблицы в качестве идентификатора в таблице студентов (std), которая полна возможных ошибок. Как вы гарантируете, что номер уникален в электронных таблицах? Даже если он уникален в одной электронной таблице, как убедиться, что в другой таблице не используются те же числа, что и в предыдущей? Или предполагая, что несколько пользователей создают электронные таблицы, в которых номера одного пользователя не перекрываются с другими пользователями, даже если все пользователи очень хорошо осведомлены о числах, которые они используют. Результат: повторяющиеся идентификационные номера.
Гораздо лучшим подходом было бы поместить уникальный ключ в столбец имени таблицы группы, а затем вставить любые имена групп из таблицы стадии в группу, отловив любые ошибки повторяющихся имен (используя при конфликте). Затем загрузите таблицу учеников непосредственно из таблицы этапов, выбрав идентификатор группы из таблицы групп по (теперь уникальному) имени группы.
create table csv_load_temp( junk_num integer, student_name text, group_name text);
create table groups( grp_id integer generated always as identity
, name text
, grp_key text generated always as ( lower(name) ) stored
, constraint grp_pk
primary key (grp_id)
, constraint grp_bk
unique (grp_key)
);
create table students (std_id integer generated always as identity
, name text
, grp_id integer
, constraint std_pk
primary key (std_id)
, constraint std2grp_fk
foreign key (grp_id)
references groups(grp_id)
);
-- Function to load Groups and Students
create or replace function establish_students()
returns void
language sql
as $$
insert into groups (name)
select distinct group_name
from csv_load_temp
on conflict (grp_key) do nothing;
insert into students (name, grp_id)
select student_name, grp_id
from csv_load_temp t
join groups grp
on (grp.name = t.group_name);
$$;
Для таблицы групп требуется Postgres v12. В предыдущих версиях удалите столбец grp_key couumn и поместите уникальное ограничение непосредственно в столбец имени. Что делать с заглавными буквами, зависит от вашей бизнес-логики.
См. fiddle для полного примера. Очевидно, что две вставки в функцию Establish_Students могут выполняться автономно и независимо друг от друга. В этом случае сама функция не нужна.
person
Belayer
schedule
15.09.2020