在处理本地托管的项目时,我一直坚持管理CSV上传。其中一项任务要求我每天上传具有新条目或现有条目更新状态的数据。某些条目(存在于数据库中)也有可能没有更新状态。
我创建了一个CSV上传功能,可将CSV文件上传到特定位置,并导入指定TABLE中的信息。 我想知道在进行CSV上传时验证数据库记录的最佳方法是什么。
理想情况下应该如下工作;
从上面可以看出,delstatus几乎每次都会更新(对于现有条目)新的CSV上传,因此需要进行检查。
我认为我们可以选择' airwaybill '检查它是否存在,和 如果是,请检查 delstatus 是否与CSV文件相同或 更新。如果' airwaybill'如果不存在,则必须添加新记录 到数据库。因为那将使我无法输入所有记录 数据库不必要。或者可以做得更好(那个 我还没去探索过。
我可以上传完整的CSV文件集,通过以下代码在数据库中创建新条目。
<?php
if(isset($_POST['csv']))
{
$sqlname= 'localhost';
$username= 'root';
$table= 'tracking';
$password= '';
$db='aatrack';
$file=$_POST['csv'];
$cons= mysqli_connect("$sqlname", "$username","$password","$db") or die(mysql_error());
$result1=mysqli_query($cons,"select count(*) count from $table");
$r1=mysqli_fetch_array($result1);
$count1=(int)$r1['count'];
mysqli_query($cons, '
LOAD DATA LOCAL INFILE "'.$file.'"
INTO TABLE '.$table.'
FIELDS TERMINATED by \',\'
LINES TERMINATED BY \'\n\'
IGNORE 1 LINES
')or die(mysql_error());
$result2=mysqli_query($cons,"select count(*) count from $table");
$r2=mysqli_fetch_array($result2);
$count2=(int)$r2['count'];
$count=$count2-$count1;
if($count>0)
{
header("location:success.php?id=$count");
}
}
?>
请您帮助指导实现同样目标的最佳方式。我知道可以通过首先将信息上传到temp_table并在LIVE表中更新条目之前比较它来完成。
请建议实现结果的最佳方式。
感谢您阅读此内容。
致以最诚挚的问候,
Amit Agnihotri
答案 0 :(得分:0)
这里有两种情况:
表格的列与csv列完全匹配。在这种情况下,REPLACE
就是答案 - 它是LOAD DATA INFILE
的关键字,请参阅doc entry
表格的列与csv列不匹配:REPLACE会导致冲突的记录被删除并重新插入,从而有效地删除了其他数据。在这种情况下,LOAD DATA INFILE
本身无效,您需要另一种方法,既可以过滤您的文件,也可以通过php或其他方法进行更新。
在任何情况下,如果你想添加更多&#34;逻辑&#34;对于导入过程,也许LOAD DATA INFIlE
并不是真正正确的方法,但使用临时表很可能会从数据库提供的所有优点中受益。
答案 1 :(得分:0)
基于UNIQUE索引,LOAD DATA INFILE会插入新记录或更新现有记录(仅当REPLACE选项处于活动状态时)。
(1)关于插入:
如果在db表中找不到UNIQUE索引列的csv输入值,则添加一条新记录,其中包含来自csv文件的(已定义)输入值。
(2)关于更新:
如果在db表中找到UNIQUE索引列的csv输入值,那么LOAD DATA INIFILE查询将执行以下操作(按此顺序!):
注意:在我的其余部分中,我将仅谈及更新部分(2)。
由于LOAD DATA INFILE在删除操作之前运行插入操作,因此您可以利用旧数据库记录在插入带有csv值的新记录时仍然存在的事实。因此,您可以根据旧记录中包含的值自定义新的输入值。其中非常酷的部分是:您甚至可以维护PRIMARY KEY字段的旧值。
关键是要定义一个 BEFORE INSERT-TRIGGER ,其中包含所有需要的自定义,验证和分配:
然后从PHP执行LOAD DATA INFILE查询。
CREATE TABLE `tracking` (
`tracking_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`odanumber` int(11) DEFAULT NULL,
`airwaybill` int(11) DEFAULT NULL,
`courierful` varchar(100) DEFAULT NULL,
`delstatus` tinyint(1) DEFAULT NULL,
`deliverydate` varchar(19) DEFAULT NULL,
PRIMARY KEY (`tracking_id`),
UNIQUE KEY `uni_airwaybill` (`airwaybill`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
USE `tests`;
DELIMITER $$
DROP TRIGGER IF EXISTS tests.tracking_BEFORE_INSERT$$
USE `tests`$$
CREATE DEFINER = CURRENT_USER TRIGGER `tests`.`tracking_BEFORE_INSERT` BEFORE INSERT ON `tracking` FOR EACH ROW
BEGIN
/* Define vars to store old record values. */
SET @old_tracking_id = NULL;
SET @old_odanumber = NULL;
SET @old_courierful = NULL;
SET @old_delstatus = NULL;
SET @old_deliverydate = NULL;
/*
Fetch the existing record if exists and pass
its values into the correspnding vars.
*/
SELECT
tracking_id,
odanumber,
courierful,
delstatus,
deliverydate
INTO
@old_tracking_id,
@old_odanumber,
@old_courierful,
@old_delstatus,
@old_deliverydate
FROM tracking
WHERE airwaybill = NEW.airwaybill
LIMIT 1;
/* If an old record was found... */
IF @old_tracking_id IS NOT NULL THEN
/* ...set the new record's tracking_id to it. */
SET NEW.tracking_id = @old_tracking_id;
/* ...and if delstatus are the same... */
IF NEW.delstatus = @old_delstatus THEN
/* ...maintain the old record values. */
SET NEW.odanumber = @old_odanumber;
SET NEW.courierful = @old_courierful;
SET NEW.deliverydate = @old_deliverydate;
END IF;
END IF;
END$$
DELIMITER ;
odanumber,airwaybill,"courierful",delstatus,"deliverydate"
19,1,abc,0,2017-04-31
25,2,def,1,2017-05-31
103,3,ghi,1,2017-06-31
324,4,jkl,1,2017-07-31
564,5,mno,0,2017-08-31
LOAD DATA INFILE "<PATH-TO>/tracking.csv"
REPLACE
INTO TABLE tests.tracking
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(odanumber, airwaybill, courierful, delstatus, deliverydate);
*)关于LOAD DATA INFILE,可能会遇到错误:
ERROR 1290(HY000):MySQL服务器正在运行 --secure-file-priv选项,因此无法执行此语句
这意味着:LOAD DATA INFILE无权读取csv文件。因此,您必须自己在数据库的配置文件(my.cnf或my.ini)中设置 secure-file-priv 。像这样:
[mysqld]
secure-file-priv = "<PATH-TO-FOLDER-CONTAINING-THE-CSV-FILES>/"
*)您无法定义运行LOAD DATA INFILE的存储过程。
最后,还有其他涉及临时表的解决方案,毫无疑问,它们可以完美地工作。其中一个在this great article中呈现。因此,触发解决方案只是另一种方法。
祝你好运!