微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

php-CSV文件上传以处理状态更新和插入新记录

在本地托管的项目上工作时,我只能管理CSV上传.一项任务要求我每天上传具有新条目或现有条目的更新状态的数据.也有可能某些条目(存在于数据库中)没有更新状态.

问题陈述;

我创建了CSV上传功能,该功能将CSV文件上传到特定位置,并将信息导入分配的TABLE中.
我想知道在执行CSV上传时验证数据库记录的最佳方法是什么.

理想情况下,它应按以下方式工作:

>如果条目不存在(从CSV文件插入新的条目基础数据)
>如果该条目存在并且状态为新上传的CSV文件,则其名称相同(IGnorE&不执行任何操作)
>如果该条目存在并且状态与新上传的CSV文件中的条目不同(更新状态为CSV文件中提到的状态)

数据库/ CSV文件结构

> tracking_id(自动递增)
> odanumber(通过CSV上载并且可以有重复的条目)
>航空运单(通过CSV和唯一性上传)
>快递(通过CSV上载并且可以有重复的条目)
> delstatus(通过CSV&进行上传内容大部分会更新)
>交货日期(通过CSV上载并随每次交货进行更新)

通过以上内容,delstatus几乎每次(对于现有条目)都会上载新CSV并进行更新,因此需要进行检查.

I assume that we can pick ‘airwaybill‘ to check if it exists, and
if it does, check if the delstatus is same as of CSV file or
update. If ‘airwaybill’ doesn’t exist then a new records must be added
to the database. As that would save me from entering all records in
database unnecessarily. Or can be done may be in a better way (that
I’m yet to explore).

现在发生了什么

我可以上传完整的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)

解决方法:

LOAD DATA INFILE如何工作

基于UNIQUE索引,LOAD DATA INFILE插入新记录或更新现有记录(仅当REPLACE选项处于活动状态时).

(1)关于插入:

如果在数据库表中未找到UNIQUE索引列的csv输入值,则将添加一条新记录,并带有csv文件中的(已定义)输入值.

(2)关于更新:

如果在数据库表中找到UNIQUE索引列的csv输入值,则LOAD DATA INIFILE查询将执行以下操作(按此顺序!):

>它将新的csv值作为具有新的PRIMARY KEY id的新记录插入;
>它将从数据库删除旧记录.

注意:在我的其余回答中,我将仅谈论更新部分(2).

INSERT-TRIGGER之前作为条件更新的解决方

由于LOAD DATA INFILE在删除操作之前先执行插入操作,因此可以利用以下事实:在插入具有csv值的新记录时,旧的db记录仍然存在.因此,您可以基于旧记录中包含的值来自定义新的输入值.其中最酷的部分是:您甚至可以保留PRIMARY KEY字段的旧值.

关键是定义一个INSERT-TRIGGER之前,其中包含所有需要的自定义,验证和分配:

>通过运行SELECT sql语句获取旧记录的值;
>将获取的值存储到预先定义的用户变量中;
>使用用户变量将旧值与csv输入值进行比较;
>基于此比较:将PRIMARY KEY字段的旧值分配为新值,并根据需要将新的csv值更改为旧值或其他值.

然后从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 ;

CSV档案(tracking.csv)

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函数(从PHP调用)

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): The MysqL server is running with the
–secure-file-priv option so it cannot execute this statement

这意味着: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.因此,触发解决方案只是另一种方法.

祝好运!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐