如何将制表符分隔文件插入到mysql中

时间:2017-11-24 10:18:05

标签: mysql

我想要的是在mysql表中插入数据,但我无法找到从一行建立关系的方法

假设我有一个文件 file.tab ,它包含类似

的数据
parent_1    parent_details_1    child_1.1   child_details_1.1   child_1.2   child_details_1.2
parent_2    parent_details_2    child_2.1   child_details_2.1
parent_3    parent_details_3    child_3.1   child_details_3.1   child_3.2   child_details_3.2   child_3.3   child_details_3.3

我想要实现的是在两个表中插入数据,如

            parent_table
+---+-----------+-------------------+
|id |   name    |      details      |
+---+-----------+-------------------+
| 1 |  parent_1 |  parent_details_1 |
| 2 |  parent_2 |  parent_details_2 |
| 3 |  parent_3 |  parent_details_3 |
+---+-----------+-------------------+


              child_table
+---+-----+-----------+-------------------+
|id | pid |   name    |      details      |
+---+-----+-----------+-------------------+
| 1 |  1  | child_1.1 | child_details_1.1 |
| 2 |  1  | child_1.2 | child_details_1.2 |
| 3 |  2  | child_2.1 | child_details_2.1 |
| 4 |  3  | child_3.1 | child_details_3.1 |
| 5 |  3  | child_3.2 | child_details_3.2 |
| 6 |  3  | child_3.3 | child_details_3.3 |
+---+-----+-----------+-------------------+

前两列是父母的,之后两列是属于孩子的,但我不知道父母有多少孩子。

我试图以这种方式加载文件。

LOAD DATA INFILE '/tmp/file.tab INTO TABLE ... 

但我接下来做什么我不知道。

如此善意地帮助我解决这个问题。

3 个答案:

答案 0 :(得分:6)

创建一个包含大量列的表(Staging)。 NULL的空(parent_id)列和子项的ID。

希望在LOAD DATA期间,'短'行会在遗失的子列中放置空值。

INSERT .. SELECT ..parentparent_detail放入Parents表格。将idsParents拉回Staging.parent_id。有关这两个SQL的详细信息位于http://mysql.rjweb.org/doc.php/staging_table#normalization

现在为每个可能的“子”列集做类似的事情:child1child1_detail(可能是NULL对)和当前的NULL child1_id。同样适用于child2 *等。请注意,在填充Children表时,您已经有parent_id可用。

这是执行任务的全SQL方式。它只比编写Perl / PHP / Java / VB /任何代码来执行任务稍微麻烦一点。

答案 1 :(得分:1)

假设Child和Parent都是Person,我只创建一个Person表,id_parent是可选的。

CREATE TABLE person (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(50) DEFAULT NULL,
  details varchar(255) DEFAULT NULL,
  id_parent1 int(11) DEFAULT NULL,
  id_parent2 int(11) DEFAULT NULL,
  PRIMARY KEY (id)
);

如何加载数据非常依赖于您喜欢的语言。 Load data infile需要静态结果表。

您拥有的行数可能不同,您需要将每行作为单个列导入。然后,您可以使用存储过程迭代它:

  • 查看cursors以了解如何迭代这样的单个列临时表的每一行。
  • 在制表符分隔符上使用replace,您可以计算出每行中的列数。
  • 然后使用while循环,您可以先开始导入子项,然后再导入父项。

平心而论,这将是一个相当复杂的存储过程,对于初学者来说可能很难写。如果您熟悉任何编程语言及其连接MySQL的方法,您可以更优雅地完成这项工作。

答案 2 :(得分:0)

如果解决方案不需要全部在SQL中,我发现预处理通常更简单。在这种情况下,将数据拆分为两个文件,这些文件可以通过LOAD DATA INFILE轻松加载(一个用于父表,一个用于子表)。

以下是使用perl

进行预处理的一种方法
my ( $parent_id, $child_id ) = ( 0, 0 );
my ( @parent_table, @child_table );
while (<>) {                    # for each line of input
  chomp;
  # split on tabs
  my ( $parent_name, $parent_detail, @child_id_detail_pairs ) = split /\t/;
  # create a row and parent_id for the parent table
  push @parent_table, [ ++$parent_id, $parent_name, $parent_detail ];

  while (@child_id_detail_pairs) { # while we have child names & details
    # remove a name and details
    my $child_name    = shift @child_id_detail_pairs;
    my $child_details = shift @child_id_detail_pairs;

    # create a row and child_id for the child table
    push @child_table, [ ++$child_id, $parent_id, $child_name, $child_details ];
  }
}

# write this to one file to load into the parent table
print "parent_table\n";
for my $row (@parent_table) {
  print join( "\t", @$row ), "\n";
}

# write this to one file to load into the child table
print "child_table\n";
for my $row (@child_table) {
  print join( "\t", @$row ), "\n";
}