Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

PHP - Importar arquivo CSV para banco de dados mysql usando LOAD DATA INFILE


Se você fizer echo($sql); antes de executá-lo, você verá que a sintaxe da sua consulta está incorreta pelos seguintes motivos:

  1. O nome do arquivo deve ser colocado entre aspas em vez de acentos graves porque é uma string literal e não um identificador.

  2. Não há absolutamente nenhuma necessidade de chamar mysql_escape_string() para especificar um delimitador em FIELDS TERMINATED BY e ENCLOSED BY e ESCAPED BY cláusulas.

  3. Você abusa dos backticks. De fato, no seu caso, como não há palavras reservadas usadas, você descarta todas elas. Eles só adicionam desordem.

  4. No final da primeira linha do seu arquivo CSV, você precisa ter ,,, porque você os usa como parte de um delimitador de linha. Se você não fizer isso, pulará não apenas a primeira linha, mas também a segunda que contém dados.

  5. Você não pode usar ENCLOSED BY cláusula mais de uma vez. Você tem que lidar com Number campo de uma forma diferente.

  6. Observando suas linhas de amostra IMHO, você não precisa de ESCAPED BY . Mas se você sentir que precisa, use-o assim ESCAPED BY '\\' .

Dito isto, uma declaração sintaticamente correta pode ser assim
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)

Agora IMHO você precisa transformar alguns campos enquanto os carrega:

  1. se date na sua tabela é de datetime tipo de dados, então ele precisa ser transformado, caso contrário, você receberá um erro

    Valor de data e hora incorreto:'18 de setembro de 2013 13:53:45' para a coluna 'data' na linha

  2. você tem que lidar com citações simples em torno de valores em Number campo

  3. você provavelmente deseja alterar "null" literal de string para NULL real para addr, pin, city, state, country colunas

  4. se a duração for sempre em segundos, você poderá extrair um valor inteiro de segundos e armazená-lo dessa maneira em sua tabela para poder agregar facilmente os valores de duração posteriormente.

Dito isto, uma versão útil da declaração deve ser algo assim
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') 

Abaixo está o resultado da execução da consulta na minha máquina
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 finalmente em php atribuindo uma string de consulta para $sql variável deve ficar assim
$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') ";