sql >> Base de Datos >  >> RDS >> Mysql

PHP - Importar archivo CSV a la base de datos mysql usando LOAD DATA INFILE

Si hicieras echo($sql); antes de ejecutarlo, verá que la sintaxis de su consulta es incorrecta por las siguientes razones:

  1. El nombre del archivo debe estar entre comillas en lugar de acentos graves porque es una cadena literal, no un identificador.

  2. No hay absolutamente ninguna necesidad de llamar a mysql_escape_string() para especificar un delimitador en FIELDS TERMINATED BY y ENCLOSED BY y ESCAPED BY cláusulas.

  3. Usas en exceso los acentos graves. De hecho en tu caso, como no se utilizan palabras reservadas, las desechas todas. Solo agregan desorden.

  4. Al final de la primera línea de su archivo CSV, debe tener ,,, porque los usa como parte de un delimitador de línea. Si no lo hace, omitirá no solo la primera línea, sino también la segunda que contiene datos.

  5. No puedes usar ENCLOSED BY cláusula más de una vez. Tienes que lidiar con Number campo de una manera diferente.

  6. Mirando sus filas de muestra en mi humilde opinión, no necesita ESCAPED BY . Pero si sientes que lo necesitas, úsalo así ESCAPED BY '\\' .

Dicho esto, una declaración sintácticamente correcta podría verse así

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)

Ahora en mi humilde opinión, necesita transformar bastantes campos mientras los carga:

  1. si date en su tabla es de datetime tipo de datos, entonces debe transformarse; de ​​lo contrario, obtendrá un error

    Valor de fecha y hora incorrecto:'18 de septiembre de 2013 01:53:45 p. m.' para la columna 'fecha' en la fila

  2. tienes que lidiar con citas únicas alrededor de valores en Number campo

  3. lo más probable es que desee cambiar "null" literal de cadena a real NULL para addr, pin, city, state, country columnas

  4. si la duración es siempre en segundos, entonces puede extraer un valor entero de segundos y almacenarlo de esa manera en su tabla para poder agregar fácilmente los valores de duración más adelante.

Dicho esto, una versión útil de la declaración debería verse así

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

A continuación se muestra el resultado de ejecutar la consulta en mi 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)

Y finalmente en php asignando una cadena de consulta a $sql la variable debería verse así

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