2011-01-13 5 views
9

Sto importando un file .csv in MySQL e tutto funziona correttamente, tranne le interruzioni di riga presenti nel file.Problema di interruzione di riga da CSV a MySQL

Uno dei miei file .csv assomiglia a questo:

42,E-A-R™ Classic™ Earplugs,ear,images/ear/classic.jpg,5%,"Proven size, shape, and foam 
3M's most popular earplug 
Corded and uncorded in a variety of individual packs 
NRR 29 dB/CSA Class AL",312-1201,,"E-A-R™ Classic™ Uncorded Earplugs, in Poly Bag",310-1001,,E-A-R™ Classic™ Uncorded Earplugs in Pillow Pack,311-1101,,"E-A-R™ Classic™ Corded Earplugs, in Poly Bag" 

Il sesto campo dovrebbe sopra rompere in una nuova linea quando viene chiamato, ma non è così. Quando si importa il file .csv, selezionare Linee terminate da \ r. Ho provato \ n e auto ma senza fortuna.

La cosa strana è che il campo sembra corretto nel database con tutte le interruzioni appropriate. Se inserisco manualmente le interruzioni di riga in PHPmyadmin, viene stampato correttamente. Ogni campo è impostato su UTF-8 pure.

Qualche idea su questo? Grazie.

modificare: qui è la dichiarazione MySQL

LOAD DATA LOCAL INFILE '/tmp/php89FC0F' REPLACE INTO TABLE `ohes_flyer_products` 
FIELDS TERMINATED BY ',' 
ENCLOSED BY '"' 
ESCAPED BY '\\' 
LINES TERMINATED BY '\r' 
+0

Cosa stai tentando di importare con inizialmente, phpMyAdmin o una console di mysql? –

+0

Immagino tu intenda il sesto campo, che inizia con "Dimostrato dimensione ... – JYelton

+1

Puoi pubblicare anche l'esatta dichiarazione DATI CARICO di MySQL che usi? – Tomalak

risposta

3

forse si potrebbe usare fgetcsv per analizzare ogni linea csv in un array e quindi scaricare tale matrice nel database?

qualcosa sulla falsariga di

$fd = fopen($csvfile, "r"); 
while ($line = fgetcsv($fd)) 
{ 
    $sql = sprintf("INSERT INTO tablename (...) VALUES ('%s', ...)", $line[0], ...); 
    $res = mysql_query($sql); 
} 

Nota 1: il codice non è pronto per la produzione, controllare iniezioni SQL!

nota 2: si prega di utilizzare istruzioni preparate poiché il loro utilizzo velocizzerà la cosa molto (o creerà una istruzione di inserimento multi-riga).

nota 3: avvolgere tutto in una transazione.

0

vostro CSV sembra essere non standard, ma che spesso la realtà di trattare con set di dati dei clienti.

Poiché strumenti come la dichiarazione di LOAD DATA di MySQL sono fatti per gestire solo il caso d'uso perfetto, ho scoperto che trattare con set di dati non standard come questo richiede un codice.

Un modo per gestire questo è innanzitutto per strofinare il CSV, sostituendo le interruzioni di linea a metà campo con una stringa speciale unica (come ===MIDFIELD_LINE_BREAK===). Quindi scriverei un parser CSV personalizzato in un linguaggio di scripting (Python, Ruby, PHP, Perl, ecc.).

Nel parser CSV, scorrere le righe nel file. Per ogni linea:

  • Scambia i \n o \r caratteri indietro nel per i ===MIDFIELD_LINE_BREAK=== caratteri.
  • Costruisce ed esegue un'istruzione INSERT.
+0

Sembra che funzioni, ma implica comunque l'inserimento manuale di === MIDFIELD_LINE_BREAK ===. Invece ho inserito manualmente \ n e sembra funzionare. Grazie comunque. – Carson

+0

Avrei dovuto specificare che quando ho pronunciato "scrubbing", intendevo che fosse uno scrubbing automatico basato su regole (ad esempio, "unisciti alla riga successiva finché non ci sono X virgole senza escape/non convalidate"). Non sapevo che il tuo set di dati fosse abbastanza piccolo da scrub manualmente, ma sono contento che abbia funzionato per te! –

7
LOAD DATA LOCAL INFILE '/tmp/php89FC0F' REPLACE INTO TABLE `ohes_flyer_products` 
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '"' 
ESCAPED BY '\\' 
LINES TERMINATED BY '\r\n' 
+0

l'aggiunta OPTIONALY prima di ENCLOSED BY era la chiave per risolvere il mio problema – miguelfg

1

Il file CSV ha alcune qualità che si può essere in grado di sfruttare.

  • il campo che contiene ritorni a capo che non terminare il record sono racchiusi tra virgolette.
  • Il ritorno a capo che indica la fine della registrazione segue un record con i dati racchiusi tra virgolette. Se ciò è vero per tutti i record, è un modo per distinguere i ritorni a capo del campo centrale dai terminatori di record.

Sapendo questo, qui ci sono alcune cose che si possono provare:

  1. Utilizzando un programma come UltraEdit (o Notepad ++) e la sua ricerca/sostituzione caratteristiche (che includono la gestione delle espressioni regolari):

    • Trova tutti i ritorni a capo preceduti da una virgoletta e sostituiscili con un carattere o una stringa univoci. Suggerisco il carattere pipe "|" ma prima assicurati che non vengano utilizzati in nessun punto del file CSV. Questi rappresenteranno la fine del record.
    • Quindi, sostituire tutti i ritorni a capo con spazi. Ciò porterà i campi con ritorni a capo indesiderati in allineamento con gli altri dati.
    • Infine, sostituire tutti i caratteri speciali di fine registrazione con ritorni a capo. Il risultato finale che gli unici ritorni a capo presenti sono gli indicatori di fine registrazione.
  2. Dato che i ritorni a capo vengono visualizzati all'interno di un campo che è racchiuso da un delimitatore (le virgolette) è possibile specificare che il motore di importazione deve onorare unico campo e registrare delimitatori fuori di citazioni. (MySQL LOAD DATA INFILE syntax) In particolare, guarda il parametro ENCLOSED BY 'char'. Poiché non tutti i campi utilizzano il delimitatore, è necessario specificare OPTIONALLY. In teoria dovresti essere in grado di specificare come è costruito il file CSV e non è necessario analizzarlo in anticipo. Sono dell'opinione, tuttavia, che i ritorni a capo del carrello debbano probabilmente essere rimossi, in modo che il testo si avvolga correttamente quando viene prodotto in un nuovo contesto.

0

Questo ha funzionato per me:

$query = <<<EOT 

LOAD DATA LOCAL INFILE '$file' REPLACE INTO TABLE `$table` 
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '"' 
ESCAPED BY '\\\' 
LINES TERMINATED BY '\\\n' 
IGNORE 1 ROWS; 

EOT; 

ho dovuto modificare @ risposta di Krunal, a causa di errori di ottenere, con l'aggiunta di un paio di in avanti in più barre.

I ritorni di riga Unix qui utilizzati, tra l'altro.

DOS:  \\\r\\\n 
Old Mac: \\\r 
Unix: \\\n 
Problemi correlati