Работая над проектом, размещенным локально, я задерживаюсь при загрузке CSV-файлов. Одна из задач требует, чтобы я ежедневно загружал данные, которые имеют либо новые записи, либо обновленный статус для существующих записей. Также существует вероятность того, что некоторые из записей (которые существуют в базе данных) не имеют обновленного состояния.
Я создал функцию загрузки CSV, которая загружает CSV-файл в определенное место и импортирует информацию в назначенную таблицу. Я хочу знать, что лучше всего проверить записи базы данных, когда я загружаю 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.
Пожалуйста, предложите оптимальный способ достижения результатов.
Спасибо, что прочитали это далеко.
С наилучшими пожеланиями,
Амит Агнихотри
На основе индекса UNIQUE LOAD DATA INFILE вставляет новую запись или обновляет существующую (только если активна опция REPLACE).
(1) Что касается вставки :
Если входное значение csv для столбца индекса UNIQUE НЕ найдено в таблице db, добавляется новая запись с (определенными) входными значениями из csv-файла.
(2) Что касается обновления :
Если входное значение csv для столбца индекса UNIQUE находится в таблице db, тогда запрос LOAD DATA INIFILE выполняет следующие операции (в этом порядке!):
NB: В оставшейся части моего ответа я буду говорить только о части обновления (2).
Поскольку LOAD DATA INFILE запускает операцию вставки перед удалением, вы можете использовать тот факт, что старая запись db все еще существует, когда вставлена новая запись со значениями csv . Таким образом, вы можете настроить новые входные значения на основе значений, содержащихся в старой записи. Действительно крутая часть этого: вы можете даже сохранить старую ценность поля PRIMARY KEY .
Ключ состоит в том, чтобы определить ПЕРЕД НАСТРОИМ-ТРИГГЕР, в котором находятся все необходимые настройки, проверки и назначения:
Затем выполните запрос LOAD DATA INFILE из PHP.
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. Поэтому вы должны установить secure-file-priv в файле конфигурации вашей базы данных (my.cnf или my.ini) самостоятельно. Как это:
[mysqld] secure-file-priv = "<PATH-TO-FOLDER-CONTAINING-THE-CSV-FILES>/"
*) Вы не можете определить хранимую процедуру, из которой запускается LOAD DATA INFILE.
В конце концов, есть и другие решения, связанные с временными таблицами, которые, без сомнения, могут работать отлично. Один из них представлен в этой замечательной статье . Таким образом, триггерное решение – это еще один подход.
Удачи!
Здесь есть два сценария:
столбцы таблицы точно соответствуют столбцам csv. в этом случае REPLACE
– это ответ – это ключевое слово для LOAD DATA INFILE
см. запись doc
столбцы таблицы не соответствуют столбцам csv: REPLACE заставит конфликтующие записи удалять и повторно вставлять, эффективно удаляя дополнительные данные. В этом случае LOAD DATA INFILE
неэффективен сам по себе, вам нужен другой подход с фильтрацией файла до этого, с обновлениями через php или каким-либо другим способом.
В любом случае, если вы хотите добавить больше «логики» в процесс импорта, возможно, LOAD DATA INFIlE
самом деле не подходит, но использование временных таблиц может быть очень полезным для всех благ.