使用外键导入 csv
Posted
技术标签:
【中文标题】使用外键导入 csv【英文标题】:Import a csv with foreignkeys 【发布时间】:2021-01-01 02:25:22 【问题描述】:假设我有 2 个表:Student 和 Groups。
Group 表有 2 列:id、GroupName Student 表有 3 列:id、StudentName 和 GroupID GroupID 是组字段的外键。我需要从 CSV 导入学生表,但在我的 CSV 中而不是组 ID 中显示组的名称。如何在不修改 csv 的情况下使用 pgAdmin 导入它?
【问题讨论】:
【参考方案1】:@LaurenzAlbe 的建议是显而易见的方法(恕我直言,从不将电子表格直接加载到 你的桌子,它们是不值得信赖的野兽)。但我相信您在加载登台后的实施 表有缺陷。 首先,使用 row_number() 几乎可以确保您获得相同组名的重复 ID。 无论先前加载的组数如何,ID 始终从 1 到 1 递增到组名称的数量,并且您无法确保后续电子表格中的顺序相同。当您有一个以前不存在的组时会发生什么。 此外,没有验证组名不存在。结果:重复的组名和/或同名的多个 ID。 其次,您尝试使用电子表格中的 id 作为学生 (std) 表中充满错误可能性的 id。您如何确保该数字在电子表格中是唯一的? 即使在单个电子表格中是唯一的,您如何确保另一个电子表格不使用与前一个相同的数字。或者假设多个用户创建电子表格,其中一个用户的编号不会与另一位用户重叠,即使所有用户 用户非常清楚他们使用的数字。结果:重复的身份证号码。 更好的方法是在组表名列上放置一个唯一键,然后将阶段表中的任何组名插入到组中,以捕获任何重复名称错误(在冲突时使用)。然后直接从stage表加载student表 同时通过(现在唯一的)组名从组表中选择组 ID。
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);
$$;
groups 表需要 Postgres v12。对于以前的版本,删除列 grp_key couumn 并将唯一约束直接放在名称列上。如何处理资本化取决于您的业务逻辑。 有关完整示例,请参见小提琴。显然,Establish_Students 函数中的 2 个插入可以独立运行。在这种情况下,函数本身就不需要了。
【讨论】:
【参考方案2】:根据 Laurenz 的回答,使用以下脚本:
创建一个临时表以从 CSV 文件插入:
CREATE TEMP TABLE std_temp (id int, student_name char(25), group_name char(25));
然后,导入 CSV 文件:
COPY std_temp FROM '/home/username/Documents/std.csv' CSV HEADER;
现在,为学生和小组创建 std
和 grp
表:
CREATE TABLE grp (id int, name char(25));
CREATE TABLE std (id int, name char(20), grp_id int);
轮到grp
表根据distinct
组名称的值填充。考虑row_number() is use to provide value for
id`:
INSERT INTO grp (id, name) select row_number() OVER (), * from (select distinct group_name from std_temp) as foo;
最后一步,根据join
选择数据,然后插入std
表中:
insert into std (id, name, grp_id) select std_temp.id, std_temp.student_name,grp.id from std_temp inner join grp on std_temp.group_name = grp.name;
最后,从最终的std
表中检索数据:
select * from std;
【讨论】:
【参考方案3】:您最简单的选择是将文件导入到像 CSV 文件一样定义的临时表中。然后您可以将该表与“groups”表连接起来,并使用INSERT INTO ... SELECT ...
填充“students”表。
当然还可以选择在两个表的连接上定义一个视图,并在视图上定义一个INSTEAD OF INSERT
触发器,将值插入到基础表中。然后您可以直接将数据加载到视图中。
【讨论】:
以上是关于使用外键导入 csv的主要内容,如果未能解决你的问题,请参考以下文章
问题:使用 phpMyAdmin Works 导入 csv,Php 脚本以不同方式处理 csv 导入