Intereting Posts

Загрузка файла CSV для обработки обновления статуса и вставки новых записей

Работая над проектом, размещенным локально, я задерживаюсь при загрузке CSV-файлов. Одна из задач требует, чтобы я ежедневно загружал данные, которые имеют либо новые записи, либо обновленный статус для существующих записей. Также существует вероятность того, что некоторые из записей (которые существуют в базе данных) не имеют обновленного состояния.

Постановка задачи;

Я создал функцию загрузки CSV, которая загружает CSV-файл в определенное место и импортирует информацию в назначенную таблицу. Я хочу знать, что лучше всего проверить записи базы данных, когда я загружаю CSV.

Он должен идеально работать следующим образом;

  1. если запись не существует (данные INSERT для новой записи из файла CSV)
  2. если запись существует и имеет статус SAME как новый загруженный CSV-файл ( IGNORE и ничего не делать)
  3. если запись существует и имеет РАЗЛИЧНЫЙ статус, чем тот, что был в новом загруженном CSV-файле (статус UPDATE соответствует тому, что упоминается в файле CSV)

Структура файла базы данных / CSV

  • tracking_id (автоинкремент)
  • odanumber (загружается через CSV и может иметь повторяющиеся записи)
  • airwaybill (загружается через CSV и UNIQUE)
  • курьером (загружается через CSV и может иметь повторяющиеся записи)
  • delstatus (загружается через CSV и в основном обновляется)
  • deliverydate (загружается через 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.

Пожалуйста, предложите оптимальный способ достижения результатов.

Спасибо, что прочитали это далеко.

С наилучшими пожеланиями,

Амит Агнихотри

Как работает LOAD DATA INFILE

На основе индекса UNIQUE LOAD DATA INFILE вставляет новую запись или обновляет существующую (только если активна опция REPLACE).

(1) Что касается вставки :

Если входное значение csv для столбца индекса UNIQUE НЕ найдено в таблице db, добавляется новая запись с (определенными) входными значениями из csv-файла.

(2) Что касается обновления :

Если входное значение csv для столбца индекса UNIQUE находится в таблице db, тогда запрос LOAD DATA INIFILE выполняет следующие операции (в этом порядке!):

  • Он вставляет новые значения csv в качестве новой записи с новым идентификатором PRIMARY KEY;
  • Он удаляет старую запись из db.

NB: В оставшейся части моего ответа я буду говорить только о части обновления (2).

ДО INSERT-TRIGGER как решение для условных обновлений

Поскольку LOAD DATA INFILE запускает операцию вставки перед удалением, вы можете использовать тот факт, что старая запись db все еще существует, когда вставлена ​​новая запись со значениями csv . Таким образом, вы можете настроить новые входные значения на основе значений, содержащихся в старой записи. Действительно крутая часть этого: вы можете даже сохранить старую ценность поля PRIMARY KEY .

Ключ состоит в том, чтобы определить ПЕРЕД НАСТРОИМ-ТРИГГЕР, в котором находятся все необходимые настройки, проверки и назначения:

  • Извлеките значения старой записи, запустив инструкцию SELECT sql;
  • Сохранять выбранные значения в ранее определенные пользовательские переменные;
  • Используйте переменные пользователя для сравнения старых значений с входными значениями csv;
  • Исходя из этих сравнений: присвойте старое значение поля PRIMARY KEY новым и измените новые значения csv на старые или на другие, если это необходимо.

Затем выполните запрос 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 ; 

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): сервер 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.

В конце концов, есть и другие решения, связанные с временными таблицами, которые, без сомнения, могут работать отлично. Один из них представлен в этой замечательной статье . Таким образом, триггерное решение – это еще один подход.

Удачи!

Здесь есть два сценария:

  1. столбцы таблицы точно соответствуют столбцам csv. в этом случае REPLACE – это ответ – это ключевое слово для LOAD DATA INFILE см. запись doc

  2. столбцы таблицы не соответствуют столбцам csv: REPLACE заставит конфликтующие записи удалять и повторно вставлять, эффективно удаляя дополнительные данные. В этом случае LOAD DATA INFILE неэффективен сам по себе, вам нужен другой подход с фильтрацией файла до этого, с обновлениями через php или каким-либо другим способом.

В любом случае, если вы хотите добавить больше «логики» в процесс импорта, возможно, LOAD DATA INFIlE самом деле не подходит, но использование временных таблиц может быть очень полезным для всех благ.