Mysql
 sql >> Base de données >  >> RDS >> Mysql

PHP - Importer un fichier CSV dans la base de données mysql à l'aide de LOAD DATA INFILE

Si vous faisiez echo($sql); avant de l'exécuter, vous verriez que la syntaxe de votre requête est incorrecte pour les raisons suivantes :

  1. Le nom de fichier doit être entouré de guillemets plutôt que de backticks car il s'agit d'une chaîne littérale et non d'un identifiant.

  2. Il n'est absolument pas nécessaire d'appeler mysql_escape_string() pour spécifier un délimiteur dans FIELDS TERMINATED BY et ENCLOSED BY et ESCAPED BY clauses.

  3. Vous abusez des backticks. En fait dans votre cas, puisqu'il n'y a pas de mots réservés utilisés, vous les abandonnez tous. Ils ne font qu'ajouter de l'encombrement.

  4. À la fin de la toute première ligne de votre fichier CSV, vous devez avoir ,,, parce que vous les utilisez dans le cadre d'un délimiteur de ligne. Si vous ne le faites pas, vous sauterez non seulement la première ligne, mais également la seconde qui contient des données.

  5. Vous ne pouvez pas utiliser ENCLOSED BY clause plus d'une fois. Vous devez composer avec Number champ d'une manière différente.

  6. En regardant vos exemples de lignes IMHO, vous n'avez pas besoin de ESCAPED BY . Mais si vous sentez que vous en avez besoin, utilisez-le comme ceci ESCAPED BY '\\' .

Cela étant dit, une déclaration syntaxiquement correcte pourrait ressembler à ceci

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)

Maintenant, à mon humble avis, vous devez transformer un certain nombre de champs pendant que vous les chargez :

  1. si date dans votre table est de datetime type de données, il doit être transformé, sinon vous obtiendrez une erreur

    Valeur datetime incorrecte :'18 septembre 2013 13:53:45' pour la colonne 'date' à la ligne

  2. vous devez gérer des qoutes simples autour des valeurs dans Number champ

  3. vous voulez probablement changer "null" littéral de chaîne en NULL réel pour addr, pin, city, state, country colonnes

  4. si la durée est toujours en secondes, vous pouvez extraire une valeur entière de secondes et la stocker de cette façon dans votre table pour pouvoir agréger facilement les valeurs de durée plus tard.

Cela étant dit, une version utile de la déclaration devrait ressembler à ceci

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

Ci-dessous le résultat de l'exécution de la requête sur ma machine

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)

Et enfin en php assignant une chaîne de requête à $sql la variable devrait ressembler à ceci

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