将多个csv文件导入到mysql表中

3

更新

我发布这个问题后的第二秒钟,通过查询结果的语法高亮,我看到了问题所在: $pl 字符串没有以闭合反引号开头。现在我已经将其更改为:

$pk = ',`%1$sUSER`,`%1$sTYPE`,`%1$sCODE`,`%1$sVALUE`,`%1$s';//WRONG
$pk = '`,`%1$sUSER`,`%1$sTYPE`,`%1$sCODE`,`%1$sVALUE`,`%1$s';//OK

然而,这带来了一个新问题:为什么PDO对象没有将错误反馈给我?手动执行查询肯定会返回一个错误,说没有名为fld2_AGE的字段,并以逗号结尾。为什么我没有得到任何错误?有什么想法吗?
PS:有什么想法可以提升SO的语法高亮来解决我的问题吗? :-)
好的,我之前编写了一个脚本,用于从一个巨大的文件中生成多个csv文件,快速将数据导入到多个mysql表中。这个脚本过去一直工作得很好(我想),直到我写了第二个脚本,在其中意外地截断了我的表格(很愚蠢,我知道)。我认为这不是什么大问题,因为我有这个脚本,恢复数据只需要几秒钟。不幸的是,我发现现在只有一个文件被导入了,而且没有显示任何错误。下面是我粘贴的整个脚本的数据库部分。当我执行这段代码时,我得到的只是输出files imported successfully,这是代码的最后一行...
我知道这是一个相当庞大的代码块,有许多字符串格式打印,这并没有改善可读性,所以我还提供了下面的查询字符串。据我所知,它们看起来格式良好,文件也是如此(我检查过)。有人能告诉我还应该在哪里寻找错误吗?这将是一个很大的帮助... 谢谢!
<?php
$files = array_fill_keys(array('filename1','filename2','filename3','filename4'),'');
//$files === array of handles fputcsv($files['filename1'],array('values','from','other','files'),';');
$tbls = array_combine($files,array('tblname1','tblname2','tblname3','tblname4'));
$path = dirname(__FILE__)'/';
$qf = 'LOAD DATA LOCAL INFILE \'%s%s.csv\' INTO TABLE my_db.tbl_prefix_%s FIELDS TERMINATED BY \';\' OPTIONALLY ENCLOSED BY \'"\' LINES TERMINATED BY \'\n\'';
$pref = array_combine($files,array('fld1_','fld2_','fld3_','fld3_'));
$pkA = ' (`%1$sNAME`,`%1$sAGE';
$pk = '`,`%1$sUSER`,`%1$sTYPE`,`%1$sCODE`,`%1$sVALUE`,`%1$s';
try
{
    $db = new PDO('mysql:host=mysqlhostn','user','pass');
    foreach($files as $f)
    {
        $db->beginTransaction();
        $db->exec(sprintf('TRUNCATE TABLE my_db.tbl_prefix_%s',$tbls[$f]));
        $db->commit();
    }
}
catch(PDOException $e)
{
    if ($db)
    {
        $db->rollBack();
        $db = null;
    }
    die('DB connection/truncate failed: '.$e->getMessage()."\n");
}
try
{
    while($f = array_shift($files))
    {
        $db->beginTransaction();
        $q = sprintf($qf,$path,$f,$tbls[$f]).sprintf($pkA.($f !== 'agent' ? $pk : ''),$pref[$f]);
        switch($f)
        {
            case 'filename3':
                $q .= 'tbl3_specific_field';
            break;
            case 'filename2':
                $q .= sprintf('tbl2_specific_field`,`%1$tbl2_specific_field2',$pref[$f]);
            break;
            case 'filename4':
                $q .= sprintf('tbl4_specific_field`,`%1$tbl4_specific_field2`,`%1$tbl4_specific_field3`,`%1$tbl4_specific_field4',$pref[$f]);
            break;
        }
        $stmt = $db->prepare($q.'`)');
        $stmt->execute();
        $db->commit();
    }
}
catch(PDOException $e)
{
    $db->rollBack();
    $e = 'CSV import Failed: '.$e->getMessage();
    $db=null;
    die($e."\n");
}
$db = null;
exit('files imported successfully'."\n");
?>

生成的查询 - 执行输出:

TRUNCATE TABLE my_db.tbl_prefix_tblname1
TRUNCATE TABLE my_db.tbl_prefix_tblname2
TRUNCATE TABLE my_db.tbl_prefix_tblname3
TRUNCATE TABLE my_db.tbl_prefix_tblname4

LOAD DATA LOCAL INFILE '/local/path/to/files/filename1.csv' INTO TABLE my_db.tbl_prefix_tblname1 FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' (`fld1_NAME`,`fld1_AGE`)
LOAD DATA LOCAL INFILE '/local/path/to/files/filename2.csv' INTO TABLE my_db.tbl_prefix_tblname2 FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' (`fld2_NAME`,`fld2_AGE,`fld2_USER`,`fld2_TYPE`,`fld2_CODE`,`fld2_VALUE`,`fld2_tbl2_specific_field`,`fld2_tbl2_specific_field2`)
LOAD DATA LOCAL INFILE '/local/path/to/files/filename3.csv' INTO TABLE my_db.tbl_prefix_tblname3 FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' (`fld3_NAME`,`fld3_AGE,`fld3_USER`,`fld3_TYPE`,`fld3_CODE`,`fld3_VALUE`,`fld3_tbl3_specific_field`)
LOAD DATA LOCAL INFILE '/local/path/to/files/filename4.csv' INTO TABLE my_db.tbl_prefix_tblname4 FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' (`fld4_NAME`,`fld4_AGE,`fld4_USER`,`fld4_TYPE`,`fld4_CODE`,`fld4_VALUE`,`fld4_tbl4_specific_field`,`fld4_tbl4_specific_field2`,`fld4_tbl4_specific_field3`,`fld4_tbl4_specific_field4`)

CSV 导入成功

File1 的导入符合我的要求,以下是第一个文件的示例内容:

11;9

而实际上未能导入的 file2 内容长这样:

11;9;25;5;FOOBAR;Z;333;321;123

两个文件的第一个字段包含相同的数据,它们的表定义、存储引擎 (InnoDB)、排序规则(UTF-8)均相同……我不知道问题出在哪里,所以希望能给予任何建议。

1个回答

1
为什么PDO对象没有对我返回错误信息?
因为MySQL在没有任何错误的情况下执行了您的查询。只是因为您编写了错误的查询,这并不意味着查询是如此错误以至于MySQL不会接受它。
每当您以编程方式生成SQL查询时,请进行验证(通过调试或者更好的单元测试),确认查询已正确创建以便于您想要完成的操作。
如果希望每次出现错误时都获取异常,请启用此功能:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

如果我尝试执行格式不正确的查询,我会收到一个1064错误。 - Elias Van Ootegem
当你收到一个错误时,你只是不检查它。你可能想为每个错误启用异常,但你需要为此配置PDO。请参见Possible PDOException Errors (MySQL 5)?Why PDO Exception Error Not Caught? - hakre
在创建连接后,我添加了$db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);。感谢您的提示!我确实测试了生成的查询,但我认为我可能不小心删除了那个字符,使用vim时,“d4”和“d5”的区别可能很大 :-) - Elias Van Ootegem
自动化测试比手动测试更好。特别是如果您让代码在大量数据上运行。 - hakre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接