Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: CSV import do MySQL
Forum PHP.pl > Forum > PHP
hettmix
Witam.

Tak szukam, szukam i nie mogę znaleźć odpowiedniego rozwiązania. Może ktoś mnie naprowadzi na właściwe tory. Dodam, że nie zajmuję się programowaniem zawodowo - raczej z doskoku.
Więc tak, mam kod, który pobiera wiersze z pliku csv:
  1. $target_path = "tmp/";
  2. $target_path = $target_path . basename( $_FILES['dane_file']['name']);
  3.  
  4. if ($_FILES['dane_file']['error']=='0') {
  5. if (move_uploaded_file($_FILES['dane_file']['tmp_name'], $target_path)) {
  6. print "Załadowano plik:&nbsp;<b>".$_FILES['dane_file']['name']."</b></br></br>";
  7.  
  8. echo "<table style=\"text-align: left; font-size: 10px; border: 3px double #aaaaaa; border-collapse: collapse;\">";
  9. $row = 0;
  10.  
  11. if (($handle = fopen("$target_path", "r")) !== FALSE) {
  12. while (($data = fgetcsv($handle, 2000, ';', '"', '\\')) !== FALSE) {
  13. if ($row == 0) {
  14. $num = count($data);
  15. echo "<thead><tr>";
  16. $row++;
  17. echo "<th style=\"padding: 7px; background: grey; border: 3px double #aaaaaa;\">".Lp."</th>";
  18. for ($c=0; $c < $num; $c++) {
  19. echo "<th style=\"padding: 7px; background: grey; border: 3px double #aaaaaa;\">" . $data[$c] . "</th>";
  20. }
  21. echo "</tr></thead>";
  22. } else {
  23. $num = count($data);
  24. echo "<tr>";
  25. $row++;
  26. $i++;
  27. echo "<td style=\"padding: 7px; border: 3px double #aaaaaa;\">" .$i. "</td>";
  28. for ($c=0; $c < $num; $c++) {
  29. $data[$c] = str_replace('""', '', $data[$c]);
  30. echo "<td style=\"padding: 7px; border: 3px double #aaaaaa;\">" . $data[$c] . "</td>";
  31. }
  32. echo "</tr>";
  33. }
  34. }
  35.  
  36. fclose($handle);
  37. echo "</table>";


Wszystko ładnie działa, poszczególne wiersze wskakują do sformatowanej tabelki i teraz chciałbym załadować te dane do tabeli w bazie MySQL. Kombinuję od jakiegoś czasu z LOAD DATA INFILE ale nie mogę tego poprawnie rozwiązać. Może jakieś sugestie ?.
cycofiasz
Zwykły insert wystarczy (o ile nie masz tam astronomicznej ilości wierszy)
hettmix
Cytat(cycofiasz @ 10.03.2012, 21:00:26 ) *
Zwykły insert wystarczy (o ile nie masz tam astronomicznej ilości wierszy)

Wierszy jest nie dużo - ok. 1000 za każdym importem. Korzystając z twojej rady naskrobałem poniższy kod:
  1. echo "<table style=\"text-align: left; font-size: 10px; border: 3px double #aaaaaa; border-collapse: collapse;\">";
  2. $row = 0;
  3.  
  4. if (($handle = fopen("$target_path", "r")) !== FALSE) {
  5. while (($data = fgetcsv($handle, 2000, ';', '"', '\\')) !== FALSE) {
  6. if ($row == 0) {
  7. $num = count($data);
  8. echo "<thead><tr>";
  9. $row++;
  10. echo "<th style=\"padding: 7px; background: grey; border: 3px double #aaaaaa;\">".Lp."</th>";
  11. for ($c=0; $c < $num; $c++) {
  12. echo "<th style=\"padding: 7px; background: grey; border: 3px double #aaaaaa;\">" . $data[$c] . "</th>";
  13. }
  14. echo "</tr></thead>";
  15. } else {
  16.  
  17. $num = count($data);
  18. echo "<tr>";
  19. $row++;
  20. $r++;
  21. echo "<td style=\"padding: 7px; border: 3px double #aaaaaa;\">" .$r. "</td>";
  22. for ($c=0; $c < $num; $c++) {
  23. $data[$c] = str_replace('""', '', $data[$c]);
  24. echo "<td style=\"padding: 7px; border: 3px double #aaaaaa;\">" . $data[$c] . "</td>";
  25. }
  26. echo "</tr>";
  27. }
  28. $data = str_replace('""', '', $data);
  29. if ($data[0][0] == 'idWniosku' || empty($data[0])) {
  30. continue; }
  31.  
  32. $tabela = "cepikdb";
  33. $separator = ";";
  34.  
  35. $sql = 'INSERT INTO `' . $tabela . '` (';
  36. $data = explode($separator, $data);
  37. if ($i == 1) {
  38. $pola = count($data);
  39.  
  40. for ($j=0; $j<$pola; $j++) {
  41.  
  42. $sql .= '`' . $data[$j] . '`';
  43.  
  44. if ($j < $count - 1) {
  45. $sql .= ', ';
  46. }
  47. }
  48. continue;
  49. }
  50.  
  51. $sql .= ') VALUES (';
  52.  
  53. for ($j=0; $j<$pola; $j++) {
  54.  
  55. $sql .= '`' . $data[$j] . '`';
  56.  
  57. if ($j < $count - 1) {
  58. $sql .= ', ';
  59. }
  60. }
  61. $sql .= ');';
  62. mysql_query($sql) or die('<b>Wystapil blad nr:</b> ' . mysql_errno() . '<br /><b>Opis bledu:</b> ' . mysql_error());
  63.  
  64. $i++;
  65. }
  66.  
  67. }
  68. echo "<p style=\"float: right; margin-top: -40px;\">( liczba wierszy: <b>$row</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;liczba pól w 1-szym wierszu: <b>$num )</b></p>";
  69. $message = 'Pomyślnie zaimportowano: ' . $i-1 . ' wierszy.';
  70. return $message;
  71.  
  72. fclose($handle);
  73. echo "</table>";


Niestety coś nie działa tak jak powinno i nie mogę tego rozgryźć. Nie wyskakuje żaden błąd, a do bazy dodaje się tylko jeden pusty rekord. Zwiększeniu o liczbę wierszy w pliku csv ulega także wartość pierwszego pola 'id', które ma ustawione auto_increment. Poniże struktura pliku csv:

idWniosku;idWewnetrzneWniosku;idUzytkownika;idPytajacego;dataZlozenia;dataWaznos
ci;dataOdpowiedzi;nazwaInstytucji
201201012100179468;;SGK;ADMIN;2012-01-01;2012-01-08;2012-01-02 00:48:09;SGKOL
viking
Myślałeś żeby:
a) Przepisać to pod PDO z przygotowanym zapytaniem i dla każdego rekordu wykonywać execute
cool.gif Objąć to blokiem transakcji bo na razie wywalenie jednego wstawia część danych

?
hettmix
Cytat(viking @ 11.03.2012, 14:16:34 ) *
Myślałeś żeby:
a) Przepisać to pod PDO z przygotowanym zapytaniem i dla każdego rekordu wykonywać execute
cool.gif Objąć to blokiem transakcji bo na razie wywalenie jednego wstawia część danych

?

Nie myślałem, bo jak już wspomniałem na wstępie programowaniem zajmuję się z od czasu do czasu. Mam teraz konkretny problem do rozwiązania i utknąłem na powyższym etapie. Może ktoś bardziej doświadczony pomoże mi wyjść na prostą. A wracając do mojego kodu to pojawił się też kolejny nieoczekiwany problem z poniższym fragmentem:
  1. if ($data[0][0] == 'idWniosku' || empty($data[0])) {
  2. continue; }

Chciałbym wykluczyć z importu pierwszy wiersz zawierający nagłówki kolumn i ta część kodu nie realizuje zakładanego celu. Próbuję to poprawić na różne sposoby ale nie wychodzi.
mortus
Ale przecież pierwszy wiersz wyklcza warunek if($row == 0), to co następuje w bloku else to przetwarzanie właściwych danych.
hettmix
Cytat(mortus @ 11.03.2012, 18:40:28 ) *
Ale przecież pierwszy wiersz wyklcza warunek if($row == 0), to co następuje w bloku else to przetwarzanie właściwych danych.

Siedzę już nad tym parę godzin i chyba się zapętliłem - mógłbyś to poprzeć fragmentem kodu ?.
mortus
Straszny misz-masz, jednocześnie wyświetlasz i dodajesz do bazy, co zdecydowanie utrudnia zrozumienie tego kodu. Tak naprawdę do kodu, którego zadaniem jest wyświetlić dane z pliku csv wystarczy dopisać 9 linijek (z uwzględnieniem nawiasów zamykających), aby te dane jednocześnie dodawać do bazy danych. Zastanowiłbym się jednak nad odseparowaniem tych dwóch funkcjonalności. Niestety w tej chwili skrypt nie ma prawa działać prawidłowo, bo w miejscu, w którym generujesz zapytanie SQL nie masz dostępu do informacji o nazwach poszczególnych kolumn tabeli w bazie danych - tablica $data jest tablicą jednowymiarową i zawiera dane pochodzące z aktualnie przetwarzanego wiersza pliku csv, Ty tymczasem używasz jej jako tablicy dwuwymiarowej (gdzieś tam w kodzie masz $data[0][0]). Proponowałbym najpierw wykonać import danych, tzn. przepisać dane z pliku do bazy danych, a później wyświetlić dane, ale już "te" pobrane z bazy. Żeby nie "zarżnąć" skryptu warto skorzystać z zapytania MULTI-INSERT i wykonywać je co np. 50 rekordów (to ze wzglądów na ograniczenia MULTI-INSERTA).
Pilsener
Najlepiej się nie rozdrabniać i użyć LOAD DATA INFILE http://dev.mysql.com/doc/refman/5.1/en/load-data.html - od razu wrzuca do bazy cały plik lub jak kto woli, robi tabelę z pliku.
Jeśli jest taka potrzeba (a zazwyczaj jest), to plik najpierw należy sparsować i dokonać w nim odpowiednich zmian (by np. liczba kolumn była zawsze identyczna). Dopiero przygotowany i zwalidowany plik wrzucać do bazy - tak jest prościej i szybciej. Inaczej nie unikniesz problemów z plikami csv gdyż niektóre programy (typu excel choćby) robią w nich niezły burdel. No i możesz obejrzeć przygotowany plik, czy odpowiada strukturze tabeli w bazie.
hettmix
Cytat(mortus @ 11.03.2012, 22:23:39 ) *
Straszny misz-masz, jednocześnie wyświetlasz i dodajesz do bazy, co zdecydowanie utrudnia zrozumienie tego kodu. Tak naprawdę do kodu, którego zadaniem jest wyświetlić dane z pliku csv wystarczy dopisać 9 linijek (z uwzględnieniem nawiasów zamykających), aby te dane jednocześnie dodawać do bazy danych. Zastanowiłbym się jednak nad odseparowaniem tych dwóch funkcjonalności. Niestety w tej chwili skrypt nie ma prawa działać prawidłowo, bo w miejscu, w którym generujesz zapytanie SQL nie masz dostępu do informacji o nazwach poszczególnych kolumn tabeli w bazie danych - tablica $data jest tablicą jednowymiarową i zawiera dane pochodzące z aktualnie przetwarzanego wiersza pliku csv, Ty tymczasem używasz jej jako tablicy dwuwymiarowej (gdzieś tam w kodzie masz $data[0][0]). Proponowałbym najpierw wykonać import danych, tzn. przepisać dane z pliku do bazy danych, a później wyświetlić dane, ale już "te" pobrane z bazy. Żeby nie "zarżnąć" skryptu warto skorzystać z zapytania MULTI-INSERT i wykonywać je co np. 50 rekordów (to ze wzglądów na ograniczenia MULTI-INSERTA).

Dzięki za uwagi, ale potrzebuję poprawnego fragmentu kodu - jak utworzyć tablicę $data dwuwymiarową, by później dostać się do konkretnych pól w odpowiednich wierszach ?.

Ok - rozwiązałem problem innym sposobem. Szkoda, że nie doczekałem się jakiejś konkretnej pomocy ze strony tego forum. Dzięki za wszelkie chęci wink.gif. Zamykam temat.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.