【问题标题】:Mysql insert into with values containing double commasMysql插入包含双逗号的值
【发布时间】:2023-04-03 20:10:01
【问题描述】:

我正在尝试将值逐行插入到MySQL 表中,该值是从Perl 中的CSV 文件中读取的。如果 CSV 文件中的任何字段为空,则将有两个连续的逗号。例如

Firstname,Lastname,Code,Phone,Email
fname1,lname1,123,34543,f1@gmail.com
fname2,lname2,344,45645,f2@gmail.com
fname3,lname3,454,,f3@gmail.com

第三行没有电话号码。所以有两个连续的逗号。当我们尝试使用以下命令插入 mysql 时,它失败了。

insert into table1 (Firstname,Lastname,Code,Phone,Email) values (fname3,lname3,454,,f3@gmail.com)

怎么做?

我使用以下代码来做到这一点。

open CSV, $file or die $!;
my @csv_content = <CSV>;
close CSV;
my $fields = "Firstname,Lastname,Code,Phone,Email";
my $table = "table1";

my $csv = Text::CSV->new();
foreach(@csv_content){
   if($csv->parse($_)){
         my @values = $csv->fields();
         my $status = $csv->combine(@values);
         my $line = $csv->string();

         $statement = "INSERT INTO $table($fields) VALUES($line);";
         $sth = $dbh->prepare( $statement );
         $sth->execute() or die "$! $DBI::errstr";
    }
}

【问题讨论】:

  • MySQL 可以使用 LOAD DATA INFILE 语法直接加载 CSV。除非您需要以某种方式预处理 CSV,否则我建议您使用它。
  • 我需要预处理 csv 所以这不是一个选项。
  • 1/ 在 SQL 中使用绑定点。 2/ prepare() 循环外的 SQL(第二点不是解决您的问题 - 它是提高代码的效率)。

标签: mysql perl csv sql-insert


【解决方案1】:

我可以这样写。我在您的 csv 文件中包含了空字段。我使用了 5 个占位符,“?”,并没有在循环内准备。只需在循环中执行即可。

my $csv = Text::CSV->new ( { binary => 1, eol => "\n" } );

my $file = 'blahblah';
open my $fh, $file or die "$file open failed: $!";

my $dbh = DBI->connect("dbi:SQLite:dbname=pedro.lite","","",
    {PrintError => 1, AutoCommit => 0}) or die "Can't connect";


my $sth = $dbh->prepare(q{INSERT INTO table1 VALUES(?,?,?,?,?)})
    or die $dbh->errstr;

<$fh>; # throw away header - first line
while (my $row = $csv->getline ($fh)) {
     $sth->execute(@$row) or die $sth->errstr;
}

$dbh->commit or die $dbh->errstr;
close $fh or die "$file close failed: $!";
$sth->finish;

如果文件开头没有标题,请不要使用该行代码。

更新:这是我用来创建数据库的实际程序(使用 SQLite),它运行良好,即使使用双逗号(空字段)。

#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV_XS;
use DBI;

my $csv = Text::CSV_XS->new ( { binary => 1, eol => "\n" } );

my $file = 'j1.csv';
open my $fh, $file or die "$file open failed: $!";

my $dbh = DBI->connect("dbi:SQLite:dbname=pedro.lite","","",
    {RaiseError => 1, PrintError => 0, AutoCommit => 0}) or die "Can't connect";

$dbh->do('DROP TABLE IF EXISTS table1');

$dbh->do(<<EOF);
CREATE TABLE table1 (
    Firstname TEXT,
    Lastname TEXT,
    Code INTEGER,
    Phone INTEGER,
    Email TEXT)
EOF

my $sth = $dbh->prepare(q{INSERT INTO table1 VALUES(?,?,?,?,?)});

<$fh>; # throw away header - first line
while (my $row = $csv->getline ($fh)) {
     $sth->execute(@$row);
}
$sth->finish;
$dbh->commit;
$dbh->disconnect;

close $fh or die "$file close failed: $!";

这是 table1 查询的输出。

sqlite> .mode column
sqlite> .width 10 10 10 10 14
sqlite> .headers on
sqlite> select * from table1;
Firstname   Lastname    Code        Phone       Email
----------  ----------  ----------  ----------  --------------
fname1      lname1      123         34543       f1@gmail.com
fname2      lname2      344         45645       f2@gmail.com
fname3      lname3      454                     f3@gmail.com
sqlite>

如您所见,它正确显示 fname3 没有电话号码。 我使用您在帖子中显示的数据插入到 table1 中。

【讨论】:

    【解决方案2】:

    计算机无法理解您要插入的内容,因为它无法理解两个逗号之间有空值。如果您是从perl 执行此操作,请尝试将每个值包含在quotes 中,即使是空值。例如,您的数据行 3 更改

    fname3,lname3,454,,f3@gmail.com
    

    'fname3','lname3','454','','f3@gmail.com'
    

    这在任何编程语言中都很容易实现。现在尝试插入。它不会抛出异常,因为它们之间的部分将是空字符串。

    【讨论】:

      【解决方案3】:

      加载此类数据的更好方法可能是使用 mysql 命令LOAD DATA INFILE:

      LOAD DATA INFILE "yourfilename" INTO TABLE "yourtablename" COLUMNS TERMINATED BY ",";
      

      从而完全避免 ,, 问题

      【讨论】:

      • 我需要从 perl 中执行此操作,直接执行此操作不是一种选择。
      • 然后您必须先将 perl 中的行预处理到不同的列中: 拆分为数组 by ,然后将数组值分配给您的插入语句中的值。这样您就可以避免空列问题,因为您只需将空值分配给一列。
      【解决方案4】:

      我用另一种方法解决了这个问题:首先用反引号将每个字段括起来,甚至是空的。用引号括起来后的数据如下所示:

      'fname1','lname1','123','34543','f1@gmail.com'
      'fname2','lname2','344','45645','f2@gmail.com'
      'fname3','lname3','454','','f3@gmail.com'
      

      这是通过编程语言完成的。经过这一步,插入数据就没有问题了。

      【讨论】:

        【解决方案5】:

        用逗号将每个值括起来,例如“fname3”、“lname3”、“454”、“”、“f3@gmail.com”。注意这里逗号之间的空引号。这样就可以了

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-20
          • 1970-01-01
          • 2011-01-01
          • 2016-03-08
          • 2012-03-22
          • 2018-07-16
          相关资源
          最近更新 更多