Mysql
 sql >> Database >  >> RDS >> Mysql

PHP - Importa file CSV nel database mysql utilizzando LOAD DATA INFILE

Se dovessi fare echo($sql); prima di eseguirlo vedresti che la sintassi della tua query non è corretta per i seguenti motivi:

  1. Il nome del file deve essere racchiuso tra virgolette anziché backtick perché è una stringa letterale non un identificatore.

  2. Non è assolutamente necessario chiamare mysql_escape_string() per specificare un delimitatore in FIELDS TERMINATED BY e ENCLOSED BY e ESCAPED BY clausole.

  3. Fai un uso eccessivo dei backtick. Infatti nel tuo caso, non essendoci parole riservate usate, le abbandoni tutte. Aggiungono solo disordine.

  4. Alla fine della prima riga del tuo file CSV devi avere ,,, perché li usi come parte di un delimitatore di riga. Se non lo farai, salterai non solo la prima riga ma anche la seconda che contiene dati.

  5. Non puoi usare ENCLOSED BY clausola più di una volta. Devi avere a che fare con Number campo in modo diverso.

  6. Guardando le tue righe di esempio IMHO non hai bisogno di ESCAPED BY . Ma se ritieni di averne bisogno, usalo in questo modo ESCAPED BY '\\' .

Detto questo, un'affermazione sintatticamente corretta potrebbe assomigliare a questa

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)

Ora IMHO devi trasformare un bel po' di campi mentre li carichi:

  1. se date nella tua tabella è di datetime tipo di dati quindi deve essere trasformato, altrimenti riceverai un errore

    Valore datetime errato:"18 settembre 2013 01:53:45" per la colonna "data" alla riga

  2. devi gestire singole qoutes attorno ai valori in Number campo

  3. molto probabilmente vuoi cambiare "null" stringa da valore letterale a NULL effettivo per addr, pin, city, state, country colonne

  4. se la durata è sempre in secondi, puoi estrarre un valore intero di secondi e memorizzarlo in questo modo nella tabella per poter aggregare facilmente i valori della durata in un secondo momento.

Detto questo, una versione utile della dichiarazione dovrebbe assomigliare a questa

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') 

Di seguito è riportato il risultato dell'esecuzione della query sulla mia macchina

mysql> LOAD DATA INFILE '/tmp/detection.csv'
    -> INTO TABLE calldetections
    -> FIELDS TERMINATED BY ','
    -> OPTIONALLY ENCLOSED BY '"' 
    -> LINES TERMINATED BY ',,,\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');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Deleted: 0  Skipped: 0  Warnings: 0

mysql> select * from calldetections;
+---------------------+---------+---------------+-------------+----------+------+------+------+-------+---------+------+------+
| date                | name    | type          | number      | duration | addr | pin  | city | state | country | lat  | log  |
+---------------------+---------+---------------+-------------+----------+------+------+------+-------+---------+------+------+
| 2013-09-18 13:53:45 | Unknown | outgoing call | 123456      |        0 | NULL | NULL | NULL | NULL  | NULL    | 0.0  | 0.0  |
| 2013-09-18 13:54:14 | Unknown | outgoing call | 1234567890  |        0 | NULL | NULL | NULL | NULL  | NULL    | 0.0  | 0.0  |
| 2013-09-18 13:54:37 | Unknown | outgoing call | 14772580369 |        1 | NULL | NULL | NULL | NULL  | NULL    | 0.0  | 0.0  |
+---------------------+---------+---------------+-------------+----------+------+------+------+-------+---------+------+------+
3 rows in set (0.00 sec)

E infine in php assegnando una stringa di query a $sql la variabile dovrebbe assomigliare a questa

$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') ";