2016-11-09 26 views
0

我有一个Bash ETL过程,它接受一个CSV文件,修复它的格式(如果需要)并将内容加载到MariaDB数据库中。我发现保存到数据库的记录少于文件中的记录,我试图理解为什么。作为该过程的一部分,我将-vv添加到mysql命令中,以查看它正在执行的操作,并且输出正在抛出我。不理解MySQL输出LOAD DATA

我正在导入的文件有行(包括标题)。

我的命令:

out=$(mysql -h ${host} \ 
     -vv \ 
     -P ${port} \ 
     -u ${user} \ 
     -p"${password}" \ 
     --local-infile \ 
     my_table < ${scriptDir}/${target}.sql 2>&1) 

相关回应看起来像这样(我加了换行):

LOAD DATA LOCAL INFILE '/tmp/mydata.csv' 
    REPLACE INTO TABLE my_table CHARACTER SET utf8 
    FIELDS TERMINATED BY ',' 
     OPTIONALLY ENCLOSED BY '"' 
    LINES TERMINATED BY '\n' 
    IGNORE 1 LINES 
    SET updated_at = NOW() 
-------------- 
Query OK, 410 rows affected, 1460 warnings 
Records: 365 Deleted: 45 Skipped: 0 Warnings: 1460 Bye 

这是第一次导入到表中。任何想法可能导致这条语句删除45条记录?

任何想法将不胜感激。

UPDATE

按照要求,这里是表的定义:

CREATE TABLE `my_table` (
    `First Name` varchar(255) DEFAULT NULL, 
    `Last Name` varchar(255) DEFAULT NULL, 
    `Company` varchar(255) DEFAULT NULL, 
    `Email` varchar(255) DEFAULT NULL, 
    `Campaign Name` varchar(255) DEFAULT NULL, 
    `Event Date` date DEFAULT NULL, 
    `Live Views Duration` varchar(255) DEFAULT NULL, 
    `On Demand Views Duration` varchar(255) DEFAULT NULL, 
    `Job Title` varchar(255) DEFAULT NULL, 
    `Reg Date` varchar(255) DEFAULT NULL, 
    `Affiliate Data` varchar(255) DEFAULT NULL, 
    `Phone 1` varchar(255) DEFAULT NULL, 
    `City` varchar(255) DEFAULT NULL, 
    `State` varchar(255) DEFAULT NULL, 
    `Postal Code` varchar(255) DEFAULT NULL, 
    `Country` varchar(255) DEFAULT NULL, 
    `Industry` varchar(255) DEFAULT NULL, 
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `updated_at` datetime DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `uix_conversion` (`Email`,`Campaign Name`,`Event Date`), 
    KEY `ix_campaign_name` (`Campaign Name`) 
) ENGINE=InnoDB AUTO_INCREMENT=512 DEFAULT CHARSET=utf8; 

UPDATE

过了一段时间了,我已经删除,没有变化的唯一指标。我还将REPLACE查询更改为IGNORE查询,现在跳过而不是删除记录。同样的净影响。而且,在多次测试同一个文件时,似乎缺少的记录并不总是相同的缺失记录。不知道这里发生了什么......

+0

您正在使用'REPLACE INTO'。你确定导入文件中没有重复记录吗?虽然我从来没有测试过,但我希望它们能够被加载,然后再被替换。 –

+0

我的版本5.7.16使用'Duplicates:'在那里,而不是'Deleted:'所以我不确定这是否可比。 –

+0

请提供表的“创建”? – Dekel

回答

1

documentation解释它很清楚:

输入行的REPLACEIGNORE关键字控制处理是唯一键值重复现有行:

  • 如果您指定REPLACE,则输入行会替换现有的行。换句话说,对于主键或唯一索引具有与现有行相同的值的行。

如果你的表是空的,当你运行LOAD DATA INFILE命令,这意味着一些你从.csv文件导入的行包含了导入到表或的PK成一列重复值列上有一个UNIQUE INDEX

如果某行是要导入包含重复的PKUNIQUE INDEX列已导入行的值的值,则REPLACE关键字使已经导入行,以腾出空间给新的被删除行(以不违反PRIMARYUNIQUE约束)。

更新了答案您发布的表定义后:搜索在id列重复,也为有在EmailCampaign NameEvent Date输入.csv文件列在同一组值的行。

更新#2(业务方案的意见后): 如果.csv文件包含在列id不是空值,这些导入的值和idAUTO_INCREMENT财产不计。

您可以跳过从导入的id柱(并让AUTO_INCREMENT完成它的工作)通过指定从.csv文件中的数据来设置列的列表:

LOAD DATA LOCAL INFILE '/tmp/mydata.csv' 
    REPLACE INTO TABLE my_table CHARACTER SET utf8 
    FIELDS TERMINATED BY ',' 
     OPTIONALLY ENCLOSED BY '"' 
    LINES TERMINATED BY '\n' 
    IGNORE 1 LINES 
    (`First Name`, `Last Name`, # put the rest of the column names here 
           # in the same order they are in the .csv file 
           # put a variable (like @a) to skip a column 
           # or to use the value in an expression in the SET clause 
    `Country`, `Industry`)  # but do not put `id` 
    SET updated_at = NOW() 

不列出现在列表中并且未在SET子句中设置的值将以其DEFAULT值(这是AUTO_INCREMENT被调用的id)设置。

+0

谢谢,但这是我的困惑的来源:'id'字段是一个自动增量。不应该重复,对吧?并且,在键入电子邮件时,数据库缺少文件中存在的多个电子邮件地址。在REPLACE场景中,它应该至少存在一次......对吗? –

+0

当且仅当您在查询中没有为其提供值(或提供NULL)时,会自动生成'id'的值。 'LOAD DATA INFILE'查询提供了一种方法来指定从文件加载哪些字段:将列的列表放置在“SET”子句之前的括号内。所有没有出现在列表中并且没有在'SET'子句中设置的字段将被设置为其默认值(这是'id'的自动递增值)。 – axiac

+0

对。我应该指定,文件中没有标识并且没有设置任何内容。这是一个唯一的标识符,只是为了方便(我们有几个自我加入的查询)。实际上,我在运行导入之前删除并重新添加它,因为它仅在运行时使用_only_进行自我连接。 –