errore con mysql insert in PDO

  • Creatore Discussione Creatore Discussione 3_g
  • Data di inizio Data di inizio

3_g

Utente Attivo
5 Set 2017
36
1
8
Ancona
devo leggere un file di testo (delimitato) e inserire le righe nei campi di un DB... e non ci sarebbe niente di strano se non fosse che la query se inserita in mysql... funziona, inserita in uno script php...no:(
il file da leggere è questo:
101|0|"Nome Cognome"|"Citta"|1|0|0|0.0|0|0|0.0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1

sono in tutto 28 valori di diverso tipo, principalmente integer poi float e testo
PHP:
$camp=23;
$textarray=file("file.txt");

for($i=0; $i<count($textarray); $i++)
{
  $text=substr($textarray[$i],0,-1);

  list($var1,$var2,$var3,$var4,$var5,$var6,$var7,$var8,$var9,$var10)=explode('|',$text);

  $database->query('INSERT INTO Tabella VALUES (
  \'\',
  :camp,
  :var1,
  :var2,
  :var3,
  :var4,
  :var5,
  :var6,
  :var9,
  :var10)');

//  $database->bind(':id', 100);
  $database->bind(':camp', $camp);
  $database->bind(':var1', $var1);
  $database->bind(':var2', $var2);
  $database->bind(':var3', str_replace('"', '', $var3));
  $database->bind(':var4', str_replace('"', '', $var4));
  $database->bind(':var5', $var5);
  $database->bind(':var6', $var6);
  $database->bind(':var9', $var9);
  $database->bind(':var10', $var10);

  $database->execute();
}

questo l'errore:
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '' for column 'ID_Dati' at row 1

questo è l'errore generato cercando di inserire un valore nullo per il campo autoicrementale


PHP:
$database->query('INSERT INTO TB_DatiGiornate VALUES (
  :id,
  :camp,
.........
 $database->bind(':id', 100);
 $database->bind(':camp', $camp);

... questo cercando di inserire un valore nel campo autoincrementale:
Fatal error: Uncaught PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '100' for key 'PRIMARY'

PHP:
  $database->query('INSERT INTO TB_DatiGiornate VALUES (
  :camp,
..............
  $database->bind(':camp', $camp);

questo cercando di fare inserire automaticamente il valore del campo autoincrementale:
Fatal error: Uncaught PDOException: SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1


PRECISAZIONI:
- per semplicità ho importato solo i primi 10 valori del file di testo;
- la tabella ha 2 ulteriori campi: ID_Dati (campo autoincrementale e camp che va valorizzato con la variabile $camp)
- ho fatto le prove anche specificando la lista completa dei campi della tabella (con e senza il campo autoincrementale)
Codice:
INSERT INTO Tabella (ID_Dati, Camp, var1, var2, var3, var4, var5, var6, var9, var10) VALUES (':id', :camp, :var1, :var2, :var3, :var4, :var5, :var6, :var9, :var10)');

oppure

INSERT INTO Tabella (Camp, var1, var2, var3, var4, var5, var6, var9, var10) VALUES (':camp, :var1, :var2, :var3, :var4, :var5, :var6, :var9, :var10)');

...di prove ne ho fatte tante ma non ho trovato quella giusta... avete qualche idea?:rolleyes:
 
Solitamente l'autoincrement non si valorizza ma si lascia la gestione dello stesso al DBMS, infatti come vedi l'errore della seconda è
Integrity constraint violation: 1062 Duplicate entry '100' for key 'PRIMARY'
ossia la chiave primaria è duplicata, in questo caso mi pare di capire che stai settando id=100 ma è già presente...

Detto questo, per la prima parte:

Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '' for column 'ID_Dati' at row 1

In questa porzione hai commesso errore di binding ossia nell'insert sono presenti 10 bind, ma tu ne passi solo 9...
Potresti abbreviare la tua query utilizzando un ciclo il che sarebbe molto più comoda la gestione:

PHP:
$values=explode('|',$text);

unset($values[0]);//elimino ID autoincrementale

$map_items=['camp','var1','var2','var3','var4','var5','var6','var7','var8','var9','var10'];
$compile_items=[];
//in questo modo mappi automaticamente i dati attraverso un'array associativo, per effettuare il bind
$query='INSERT INTO Tabella';
$type='';
$inter_=[];
foreach($map_items as $k=>$v){
$compile_items[$v]=$values[$k+1];
//non è lo scopo corretto lo inserisco solo a scopo illustrativo, dovrebbe essere processato da un QB apposito e no da iterazione
$inter_[]='?';
switch($k){
 //da implementare la tipologia per il binding
/*sarebbe utili reperire la tipologia dei dati sul db in modo automatico passando la tipologia creando un querybuilder o utilizzandone uno già pronto*/
    default:$type.='i';
}
}
//in questo modo la nostra query si costruisce in automatico
$query.='('.join(',',array_keys($compile_items)).') VALUES ('.join(',',$inter_)).')';

$this->conn->execute_stmt($query,$compile_items,$type)->result;

Per effettuare il binding qua ci sta un metodo:
https://forum.mrw.it/threads/php-ricerca-record-tramite-post.52470/#post-204377


Potresti pensare di utilizzare qualche lib o framework di supporto per la gestione e lavorazione dei dati.. medoo.in (https://medoo.in/) non è affatto male.
 
ma la prova lasciando che il campo si valorizzasse da solo l'ho fatta (non ho riportato l'errore:() ma non funziona lo stesso
INSERT INTO Tabella (Camp, var1, var2, var3, var4, var5, var6, var9, var10) VALUES (':camp, :var1, :var2, :var3, :var4, :var5, :var6, :var9, :var10)');
questa sera la faccio "girare" e riporto l'errore

il valore '100' non è presente (la tabella ha 1 solo record registrato) l'ho inserito di proposito per "vedere" cosa succedeva...

non ho ancora padronanza del PHP per cui cerco di fare le cose semplici... e non mi riescono neanche quelle:(:(
il tuo codice e molto più efficiente ma vorrei aspettare di implementarlo per capire prima dove è l'errore nella mia query;)

nel 1 caso il binding corrisponde (9 su 9) il primo valore \'\' è per passare un valore nullo al campo autoincrementale per far si che sia il DBMS a metterlo... ho fatto la prova anche togliendo questo "valore" e lasciando solo i 9 binding...
diciamo che di prove/combinazioni (anche ad minchiam:eek:) ne ho fatte tante... perchè finite le soluzioni "logiche" per me... ho iniziato ad andare nel pallone:D
 
nel 1 caso il binding corrisponde (9 su 9) il primo valore \'\' è per passare un valore nullo al campo autoincrementale per far si che sia il DBMS a metterlo...
in realtà no, l'autoincrement non dovrebbe essere passato.

Prova a creare una tabella senza autoincrement e senza vincoli vedi cosa succede.... se i dati vengono inseriti è come ti dico io....
 
già provato;)
rimane il fatto che la query inserita in mysql funziona... messa con il PDO/binding... no

forse ci sono dei parametri da tener conto in base a come è fatta la tabella... stasera vi posto la struttura... precisa:)
 
mi è venuto un dubbio... nella classe che uso (presa su interneto_O) la funzione bind è fatta così:
PHP:
    // funzione bind
    public function bind($param, $value, $type = null) {
        if (is_null($type)) {
            switch (true) {
                case is_int($value):
                    $type = PDO::PARAM_INT;
                    break;
                case is_bool($value):
                    $type = PDO::PARAM_BOOL;
                    break;
                case is_null($value):
                    $type = PDO::PARAM_NULL;
                    break;
                default:
                    $type = PDO::PARAM_STR;
            }
        }
        $this->stmt->bindValue($param, $value, $type);
    }

il problema di inserimento può derivare da questa??
 
prove in diretta:eek:...
struttura delle tabelle del db:
PHP:
CREATE TABLE `Tabella1` (
  `ID_Dati` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `Camp` int(11) NOT NULL,
  `field1` tinyint(4) DEFAULT NULL,
  `field2` varchar(100) DEFAULT NULL,
  `field3` varchar(20) DEFAULT NULL,
  `field4` tinyint(4) DEFAULT NULL,
  `field5` float DEFAULT NULL,
  `field6` tinyint(4) DEFAULT NULL,
  `field7` int(11) DEFAULT NULL
) ENGINE=InnoDB;

CREATE TABLE `Tabella2` (
  `Camp` int(11) NOT NULL,
  `field1` tinyint(4) DEFAULT NULL,
  `field2` varchar(100) DEFAULT NULL,
  `field3` varchar(20) DEFAULT NULL,
  `field4` tinyint(4) DEFAULT NULL,
  `field5` float DEFAULT NULL,
  `field6` tinyint(4) DEFAULT NULL,
  `field7` int(11) DEFAULT NULL
) ENGINE=InnoDB;

dati da inserire (file.txt):
Codice:
101|"Nome Cognome"|"citta"|1|0.0|5|1
102|"Nome Cognome"|"citta"|2|0.1|4|1
103|"Nome Cognome"|"citta"|3|0.2|3|1
104|"Nome Cognome"|"citta"|4|0.3|2|1
105|"Nome Cognome"|"citta"|5|0.4|1|1

codice "fisso" dello script (la parentesi graffa di chiusura del for è riportata alla fine dello script:
PHP:
$database = new Database($db, $u, $p);

$camp=23;
$textarray=file("file.txt");

for($i=0; $i<count($textarray); $i++)
{
  $text=substr($textarray[$i],0,-1);

  list($var1,$var2,$var3,$var4,$var5,$var6,$var7)=explode('|',$text);

1^ prova effettuata con questa query:
PHP:
  $database->query('INSERT INTO Tabella1 VALUES (:camp, :var1, :var2, :var3, :var4, :var5, :var6, :var7)');

  $database->bind(':camp', $camp);
  $database->bind(':var1', $var1);
  $database->bind(':var2', str_replace('"', '', $var2));
  $database->bind(':var3', str_replace('"', '', $var3));
  $database->bind(':var4', $var4);
  $database->bind(':var5', $var5);
  $database->bind(':var6', $var6);
  $database->bind(':var7', $var7);

  $database->execute();

errore generato:
Fatal error: Uncaught PDOException: SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1
 
2^ prova effettuata con questa query:
PHP:
  $database->query('INSERT INTO Tabella2 VALUES (:camp, :var1, :var2, :var3, :var4, :var5, :var6, :var7)');
 
  $database->bind(':camp', $camp);
  $database->bind(':var1', $var1);
  $database->bind(':var2', str_replace('"', '', $var2));
  $database->bind(':var3', str_replace('"', '', $var3));
  $database->bind(':var4', $var4);
  $database->bind(':var5', $var5);
  $database->bind(':var6', $var6);
  $database->bind(':var7', $var7);

  $database->execute();

FUNZIONA:)
 
3^ prova effettuata con questa query:
PHP:
  $database->query('INSERT INTO Tabella1 (ID_Dati, Camp, field1, field2, field3, field4, field5, field6, field7) VALUES ('', :camp, :var1, :var2, :var3, :var4, :var5, :var6, :var7)');

  $database->bind(':camp', $camp);
  $database->bind(':var1', $var1);
  $database->bind(':var2', str_replace('"', '', $var2));
  $database->bind(':var3', str_replace('"', '', $var3));
  $database->bind(':var4', $var4);
  $database->bind(':var5', $var5);
  $database->bind(':var6', $var6);
  $database->bind(':var7', $var7);

  $database->execute();
errore generato:
Parse error: syntax error, unexpected '', :camp, :var1, :var2, :var3,' (T_CONSTANT_ENCAPSED_STRING), expecting ',' or ')'
 
4^ prova effettuata con questa query:
PHP:
  $database->query('INSERT INTO Tabella1 (Camp, field1, field2, field3, field4, field5, field6, field7) VALUES (:camp, :var1, :var2, :var3, :var4, :var5, :var6, :var7)');

  $database->bind(':camp', $camp);
  $database->bind(':var1', $var1);
  $database->bind(':var2', str_replace('"', '', $var2));
  $database->bind(':var3', str_replace('"', '', $var3));
  $database->bind(':var4', $var4);
  $database->bind(':var5', $var5);
  $database->bind(':var6', $var6);
  $database->bind(':var7', $var7);

  $database->execute();
FUNZIONA CON QUESTA STRUTTURA DI DATI;);)... semplificata per fare le prove... ma con i dati "veri" no:confused::confused:

la caccia continua:D:D:D
 
1^ prova effettuata con questa query:
dovresti rifare la prova scrivendo bene la query,
considera anche la differenza tra virgolette e apici ….
Codice:
$database->query("
INSERT INTO Tabella1
(Camp, field1, field2, field3, field4, field5, field6, field7)
VALUES
(:camp, :var1, :var2, :var3, :var4, :var5, :var6, :var7)
");

se non indichi i campi della tabella, come nel tuo esempio, il motore del db potrebbe "confondersi" perché ha un campo in più, l'autoincrement
 
Ultima modifica:
4^ prova effettuata con questa query:
vedi quanto detto per la prova3, poi se puoi posta la query definitiva

ps, nei miei sviluppi le query sono sempre complete, lista delle colonne e conseguenti valori, vedi suggerimento prova 1
in questo modo, se qualcuno facesse variazioni al db, che dovesso renderlo incongruente rispetto all'applicazione,
verrebbe segnalato un errore nell'esecuzione della query
sono contrario a creare automatismi per associare dati a colonne,
solito esempio estremo,
se dalla tabella fatture venisse eliminata la colonna iva, per sbaglio, l'automatismo garantirebbe il funzionamento dell'applicazione,
ma sai cosa significa perdere la colonna iva, senza che nessuno se ne accorge?

quindi sviluppa in modo "sicuro", garantendo sempre il risultato ….
 
da buon ultimo,
mi sono creato miei metodi "estendendo" la classe PDO
preferisco usare il posizionale "?" invece dell'associazione come fai tu
questa è uno dei miei metodi,
PHP:
  private function BindParams($sql, $params)
  {
    if($this->AllowLog) $this->MyLog($this->pdoSqlDebug($sql, $params));

    if (substr_count($sql, "?") != count($params))
      $this->MyErr("PDO : incongruenza nei parametri della query -> ".$sql);

    $params = $this->FixSQL($params);

    try { $sth = $this->pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
          $sth->execute($params);
          return $sth; }
    catch(PDOException $e){ $this->handle_sql_errors($sql, $e, $params); }
  }

quando le tue query funzionano, prova ad inserire come nome "D'Alessandro" e vedi che succede
poi pensa a "FixSQL" che leggi nel mio codice
 
Per quanto riguarda la tipologia di dato appoggiati alla tabella information schema, senza andare lontano potresti utilizzare librerie di terze parti vedi medoo.in che ha tutti i metodi scritti abbastanza bene ampiamente documentato facilmente estensibile...
Giusto per conoscenza, potresti utilizzare Eloquent di Laravel, che di tutta la diatribia scritta non ne vedrai neanche l'ombra, una semplice Eloquent::Insert($dati);
;)
 
una semplice Eloquent::Insert($dati);
ma con pochi metodi ben scritti, estendendo la classe pdo, puoi ottenere lo stesso risultato, esempio
PHP:
public function queryM($sql, $params=array())  // return the number of the involved rows (insert, update, delete)
{
    return $this->BindParams($sql, $params)->rowCount();
}


$dbresult = $db->queryM($sql, array($car['cod'], $car['descr'], $car['um'], $car['sort'], $car['aggior'], $car['nr']));
ed hai "in mano" il tuo codice che rendi più funzionale alle tue necessità

eloquente, no ?
 
Ultima modifica:

Discussioni simili