У меня есть данные файла .csv, подобные этому
Date,Name,Call Type,Number,Duration,Address,PostalCode,City,State,Country,Latitude,Longitude "Sep-18-2013 01:53:45 PM","Unknown","outgoing call",'123456',"0 Secs","null","null","null","null","null",0.0,0.0,,, "Sep-18-2013 01:54:14 PM","Unknown","outgoing call",'1234567890',"0 Secs","null","null","null","null","null",0.0,0.0,,, "Sep-18-2013 01:54:37 PM","Unknown","outgoing call",'14772580369',"1 Secs","null","null","null","null","null",0.0,0.0,,,
и я использую следующий код для вставки данных в базу данных
$sql = "LOAD DATA INFILE `detection.csv` INTO TABLE `calldetections` FIELDS TERMINATED BY '".@mysql_escape_string(","). "` OPTIONALLY ENCLOSED BY `".@mysql_escape_string("\""). "` OPTIONALLY ENCLOSED BY `".@mysql_escape_string("\'"). "` ESCAPED BY `".@mysql_escape_string("\\"). "` LINES TERMINATED BY `".",,,\\r\\n". "`IGNORE 1 LINES `" ."(`date`,`name`,`type`,`number`,`duration`,`addr`,`pin`,`city`,`state`,`country`,`lat`,`log`)"; $res = @mysql_query($con,$sql);
но ничего не вставлено; где ошибка?
Если вы сделаете echo($sql);
перед его выполнением вы увидите, что синтаксис вашего запроса неверен по следующим причинам:
Имя файла должно быть заключено в кавычки, а не обратно, потому что это строковый литерал, а не идентификатор.
Абсолютно нет необходимости вызывать mysql_escape_string()
чтобы указать разделитель в ESCAPED BY
FIELDS TERMINATED BY
и ENCLOSED BY
и ESCAPED BY
.
Вы злоупотребляете бэкпиксом. На самом деле, в вашем случае, поскольку нет зарезервированных слов, вы бросаете их все. Они только добавляют беспорядок.
В конце самой первой строки вашего CSV-файла вы должны иметь ,,,
потому что вы используете их как часть разделителя строк. Если вы этого не сделаете, вы пропустите не только первую строку, но и вторую, которая содержит данные.
Вы не можете использовать предложение ENCLOSED BY
более одного раза. Вы должны иметь дело с полем Number
по-другому.
Глядя на ваши образцы строк IMHO, вам не нужен ESCAPED BY
. Но если вы чувствуете, что вам нужно, используйте его так, как этот ESCAPED BY '\\'
.
При этом синтаксически корректное утверждение может выглядеть так:
LOAD DATA INFILE 'detection.csv' INTO TABLE calldetections FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY ',,,\r\n' IGNORE 1 LINES (date, name, type, number, duration, addr, pin, city, state, country, lat, log)
Теперь IMHO вам нужно преобразовать немало полей, пока вы их загружаете:
если date
в вашей таблице имеет datetime
данных datetime
тогда ее необходимо преобразовать, иначе вы получите сообщение об ошибке
Неверное значение даты и времени: «Sep-18-2013 01:53:45 PM» для столбца «дата» в строке
вам нужно иметь дело с одиночными qoutes вокруг значений в поле Number
вы, скорее всего, захотите изменить "null"
строковый литерал на фактический NULL
для столбцов addr, pin, city, state, country
если продолжительность всегда в секундах, вы можете извлечь целое значение секунд и сохранить его таким образом в своей таблице, чтобы иметь возможность легко суммировать значения продолжительности позже.
При этом полезная версия утверждения должна выглядеть примерно так:
LOAD DATA INFILE 'detection.csv' INTO TABLE calldetections FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY ',,,\r\n' IGNORE 1 LINES (@date, name, type, @number, @duration, @addr, @pin, @city, @state, @country, lat, log) SET date = STR_TO_DATE(@date, '%b-%d-%Y %h:%i:%s %p'), number = TRIM(BOTH '\'' FROM @number), duration = 1 * TRIM(TRAILING 'Secs' FROM @duration), addr = NULLIF(@addr, 'null'), pin = NULLIF(@pin, 'null'), city = NULLIF(@city, 'null'), state = NULLIF(@state, 'null'), country = NULLIF(@country, 'null')
Ниже приведен результат выполнения запроса на моей машине
mysql> LOAD DATA INFILE '/tmp/detection.csv' -> INTO TABLE calldetections -> ПОЛИГРАФИИ, ПРЕРЫВАННЫЕ ',' -> ДОПОЛНИТЕЛЬНО ЗАВЕРШЕНО '' ' -> LINES TERMINATED BY ',,, \ n' -> IGNORE 1 ЛИНИИ -> (@date, name, type, @number, @duration, @addr, @pin, @city, @state, @country, lat, log) -> SET date = STR_TO_DATE (@date, '% b-% d-% Y% h:% i:% s% p'), -> number = TRIM (BOTH '\' 'FROM @number), -> duration = 1 * TRIM (TRAILING 'Secs' FROM @duration), -> addr = NULLIF (@addr, 'null'), -> pin = NULLIF (@pin, 'null'), -> city = NULLIF (@city, 'null'), -> state = NULLIF (@state, 'null'), -> country = NULLIF (@country, 'null'); Запрос ОК, 3 строки затронуты (0.00 сек) Записей: 3 Удалено: 0 Пропущено: 0 Предупреждения: 0 mysql> select * from calldetections; + --------------------- + --------- + --------------- + - ------------ + ---------- + ------ + ------ + ------ + ----- - + --------- + ------ + ------ + | дата | имя | тип | номер | продолжительность | addr | pin | город | состояние | страна | lat | log | + --------------------- + --------- + --------------- + - ------------ + ---------- + ------ + ------ + ------ + ----- - + --------- + ------ + ------ + | 2013-09-18 13:53:45 | Неизвестно | исходящий звонок | 123456 | 0 | NULL | NULL | NULL | NULL | NULL | 0.0 | 0.0 | | 2013-09-18 13:54:14 | Неизвестно | исходящий звонок | 1234567890 | 0 | NULL | NULL | NULL | NULL | NULL | 0.0 | 0.0 | | 2013-09-18 13:54:37 | Неизвестно | исходящий звонок | 14772580369 | 1 | NULL | NULL | NULL | NULL | NULL | 0.0 | 0.0 | + --------------------- + --------- + --------------- + - ------------ + ---------- + ------ + ------ + ------ + ----- - + --------- + ------ + ------ + 3 ряда в наборе (0,00 сек)
И, наконец, в php присвоение строки запроса переменной $sql
должно выглядеть так:
$sql = "LOAD DATA INFILE 'detection.csv' INTO TABLE calldetections FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY ',,,\\r\\n' IGNORE 1 LINES (@date, name, type, @number, @duration, @addr, @pin, @city, @state, @country, lat, log) SET date = STR_TO_DATE(@date, '%b-%d-%Y %h:%i:%s %p'), number = TRIM(BOTH '\'' FROM @number), duration = 1 * TRIM(TRAILING 'Secs' FROM @duration), addr = NULLIF(@addr, 'null'), pin = NULLIF(@pin, 'null'), city = NULLIF(@city, 'null'), state = NULLIF(@state, 'null'), country = NULLIF(@country, 'null') ";
mysqli_query($cons, ' LOAD DATA LOCAL INFILE "'.$file.'" INTO TABLE tablename FIELDS TERMINATED by \',\' LINES TERMINATED BY \'\n\' IGNORE 1 LINES (isbn10,isbn13,price,discount,free_stock,report,report_date) SET RRP = IF(discount = 0.00,price-price * 45/100,IF(discount = 0.01,price,IF(discount != 0.00,price-price * discount/100,@RRP))), RRP_nl = RRP * 1.44 + 8, RRP_bl = RRP * 1.44 + 8, ID = NULL ')or die(mysqli_error()); $affected = (int) (mysqli_affected_rows($cons))-1; $log->lwrite('Inventory.CSV to database:'. $affected.' record inserted successfully.');
RRP и RRP_nl и RRP_bl не находятся в csv, но мы вычисляем это и после вставки.