CSV 文件数据到 PostgreSQL 表中

Posted

技术标签:

【中文标题】CSV 文件数据到 PostgreSQL 表中【英文标题】:CSV file data into a PostgreSQL table 【发布时间】:2016-05-06 14:18:08 【问题描述】:

我正在尝试为电影镜头 (http://grouplens.org/datasets/movielens/) 创建一个数据库。我们有电影和收视率。电影有多种类型。我把它们分成一个单独的表,因为它是一个 1:many 关系。用户与电影之间也存在多:多关系。我需要能够以多种方式查询此表。

所以我创建了:

CREATE TABLE genre (
  genre_id serial NOT NULL,
  genre_name char(20) DEFAULT NULL,
  PRIMARY KEY (genre_id)
) 

.

INSERT INTO genre VALUES 
  (1,'Action'),(2,'Adventure'),(3,'Animation'),(4,'Children\s'),(5,'Comedy'),(6,'Crime'),
  (7,'Documentary'),(8,'Drama'),(9,'Fantasy'),(10,'Film-Noir'),(11,'Horror'),(12,'Musical'),
  (13,'Mystery'),(14,'Romance'),(15,'Sci-Fi'),(16,'Thriller'),(17,'War'),(18,'Western');

.

CREATE TABLE movie (
  movie_id int NOT NULL DEFAULT '0',
  movie_name char(75) DEFAULT NULL,
  movie_year smallint DEFAULT NULL,
  PRIMARY KEY (movie_id)
  );

.

CREATE TABLE moviegenre (
  movie_id int NOT NULL DEFAULT '0',
  genre_id tinyint NOT NULL DEFAULT '0',
  PRIMARY KEY (movie_id, genre_id)
);

我不知道如何导入包含movie_id、movie_name 和movie_genre 列的movies.csv 例如,第一行是(1;Toy Story (1995);Animation|Children's|Comedy) 如果我手动插入,它应该是这样的:

INSERT INTO moviegenre VALUES (1,3),(1,4),(1,5)

因为3是动画,4是儿童,5是喜剧

如何以这种方式导入所有数据集?

【问题讨论】:

如何使用 COPY 上传数据?或者你编辑文本文件? 我使用 COPY 上传我的数据 【参考方案1】:

您应该首先创建一个可以从 CSV 文件中提取数据的表:

CREATE TABLE movies_csv (
  movie_id    integer, 
  movie_name  varchar,
  movie_genre varchar
);

请注意,任何单引号 (Children's) 都应加倍 (Children''s)。一旦数据在这个暂存表中,您可以将数据复制到movie 表中,该表应具有以下结构:

CREATE TABLE movie (
  movie_id   integer, -- A primary key has implicit NOT NULL and should not have default
  movie_name varchar NOT NULL, -- Movie should have a name, varchar more flexible
  movie_year integer,          -- Regular integer is more efficient
  PRIMARY KEY (movie_id)
);

同样对其他桌子进行消毒。

现在复制数据,从 CSV 名称中提取简单的名称和年份:

INSERT INTO movie (movie_id, movie_name)
  SELECT parts[1], parts[2]::integer
  FROM movies_csv, regexp_matches(movie_name, '([[:ascii:]]*)\s\(([\d]*)\)$') p(parts)

regular expression 说:

([[:ascii:]]*) - 捕获所有字符,直到下面的匹配项 \s - 读过去一个空格 \( - 阅读左括号 ([\d]*) - 捕获任何数字 \) - 读完右括号 $ - 从字符串末尾开始匹配

因此,在输入“Die Hard 17(约翰永生)(2074)”时,它会创建一个带有'Die Hard 17 (John lives forever)', '2074' 的字符串数组。扫描必须从结尾 $ 开始,假设所有电影标题都以括号中的出版年份结尾,以便在电影标题中保留括号和数字。

现在您可以处理电影类型了。您必须使用regex_split_to_table() 函数拆分条上的字符串|,然后加入流派名称上的genre 表:

INSERT INTO moviegenre
  SELECT movie_id, genre_id
  FROM movies_csv, regexp_split_to_table(movie_genre, '\|') p(genre) -- escape the |
  JOIN genre ON genre.genre_name = p.genre;

完成所有操作后,您可以删除movies_csv 表。

【讨论】:

很好的解释!非常感谢!

以上是关于CSV 文件数据到 PostgreSQL 表中的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL如何导入数据

PostgreSQL:将数据导出到 csv 文件

将 CSV 导入到 postgreSQL 中的表中,忽略重复项 - 亚马逊 AWS/RDS

如何在不先定义表中的列的情况下将数据加载到 PostgreSQL 中?

如何从 postgreSQL 表中检索随机数据行?

如何将具有自定义枚举类型的数据从 csv 插入现有的 PostgreSQL 表