Come inserisco valori NULL utilizzando PDO?


105

Sto usando questo codice e sono oltre la frustrazione:

try {
    $dbh = new PDO('mysql:dbname=' . DB . ';host=' . HOST, USER, PASS);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
catch(PDOException $e)
{
    ...
}
$stmt = $dbh->prepare('INSERT INTO table(v1, v2, ...) VALUES(:v1, :v2, ...)');
$stmt->bindParam(':v1', PDO::PARAM_NULL); // --> Here's the problem

PDO::PARAM_NULL, null, '', tutti falliscono e lanciano questo errore:

Errore irreversibile : impossibile passare il parametro 2 per riferimento in / opt / ...

Risposte:


138

Sto solo imparando PDO, ma penso che tu debba usare bindValue, nobindParam

bindParamaccetta una variabile per fare riferimento e non inserisce un valore al momento della chiamata bindParam. Ho trovato questo in un commento sui documenti php:

bindValue(':param', null, PDO::PARAM_INT);

EDIT: PS Potresti essere tentato di farlo bindValue(':param', null, PDO::PARAM_NULL);ma non ha funzionato per tutti (grazie Will Shaver per la segnalazione.)


Non sono sicuro della differenza tra questi due, ma indagherò su alcuni. Grazie, anche la tua risposta è stata fantastica.
Nacho

3
Penso che questa potrebbe essere una risposta migliore della mia (se funziona davvero)
Joe Phillips

2
Ho avuto problemi con PDO :: PARAM_NULL su MySql 5.1.53, ma PDO :: PARAM_INT con un valore nullo ha funzionato alla grande.
Will Shaver

2
Odin: Penso che la parte più importante sia passare tutti e tre i parametri :). nella domanda di ign stava passando PDO :: PARAM_NULL come valore, invece che come tipo (e non passando affatto un tipo.)
JasonWoof

1
Cordiali saluti: nella maggior parte dei casi stai completamente bene con l'utilizzo di bindValue()over bindParam(); per tutto, non solo per il NULLvalore. Non riesco a pensare a un singolo caso in cui dovresti associare il parametro a un riferimento di una variabile PHP, ma è quello che bindParam()fa.
low_rents

48

Quando si utilizza bindParam()è necessario passare una variabile, non una costante. Quindi prima di quella riga è necessario creare una variabile e impostarla sunull

$myNull = null;
$stmt->bindParam(':v1', $myNull, PDO::PARAM_NULL);

Riceverai lo stesso messaggio di errore se provassi:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);

Hai capito bene, mi sono appena reso conto di averlo fatto prima nel mio codice, $ null = PDO :: PARAM_NULL; Grazie.
Nacho

1
È meglio usare bindValue () in questo caso, se vuoi comunque creare dei segnaposto. bindParam () è originariamente concepito per eseguire una query, quindi modificare le variabili e rieseguire senza associare nuovamente i parametri. bindValue () si collega immediatamente, bindParam () solo in esecuzione.
Hugo Zink

1
Ho scoperto che null deve essere minuscolo nella riga $ myNull = null. $ myNull = NULL NON ha funzionato.
raphael75

28

Quando si utilizzano INTEGERcolonne (che possono essere NULL) in MySQL, PDO ha un comportamento (secondo me) inaspettato.

Se si utilizza $stmt->execute(Array), è necessario specificare il valore letterale NULLe non è possibile fornire NULLun riferimento alla variabile. Quindi questo non funzionerà:

// $val is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => $val
));
// will cause the error 'incorrect integer value' when $val == null

Ma questo funzionerà:

// $val again is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => isset($val) ? $val : null
));
// no errors, inserts NULL when $val == null, inserts the integer otherwise

Ho provato questo su MySQL 5.5.15 con PHP 5.4.1


1
$ stmt-> execute (array (': param' =>! empty ($ val)? $ val: null)); Usa! Vuoto perché per una stringa vuota vorresti anche impostare null nel database
Shehzad Nizamani

1
@ShehzadNizamani Solo se il tipo di colonna è intero, come nel suo esempio, sì. Ma per il resto si isset()correla meglio a NULL. Anche una stringa vuota è un valore.
StanE

8

Per coloro che hanno ancora problemi (Impossibile passare il parametro 2 per riferimento), definire una variabile con valore nullo, non passare semplicemente nullo a PDO:

bindValue(':param', $n = null, PDO::PARAM_INT);

Spero che questo ti aiuti.


6

Ho avuto lo stesso problema e ho trovato questa soluzione funzionante con bindParam:

    bindParam(':param', $myvar = NULL, PDO::PARAM_INT);

3

Se vuoi inserire NULLsolo quando valueè emptyo '', ma inserisci valuequando è disponibile.

A) Riceve i dati del modulo utilizzando il metodo POST e chiama l'inserimento della funzione con quei valori.

insert( $_POST['productId'], // Will be set to NULL if empty    
        $_POST['productName'] ); // Will be to NULL if empty                                

B) Valuta se un campo non è stato compilato dall'utente e lo inserisce NULLse è così.

public function insert( $productId, $productName )
{ 
    $sql = "INSERT INTO products (  productId, productName ) 
                VALUES ( :productId, :productName )";

    //IMPORTANT: Repace $db with your PDO instance
    $query = $db->prepare($sql); 

    //Works with INT, FLOAT, ETC.
    $query->bindValue(':productId',  !empty($productId)   ? $productId   : NULL, PDO::PARAM_INT); 

    //Works with strings.
    $query->bindValue(':productName',!empty($productName) ? $productName : NULL, PDO::PARAM_STR);   

    $query->execute();      
}

Ad esempio, se l'utente non inserisce nulla nel productNamecampo del modulo, $productNamesarà SETma EMPTY. Quindi, è necessario controllare se lo è empty(), e se lo è, quindi inserire NULL.

Testato su PHP 5.5.17

In bocca al lupo,


3
Oppure puoi usare la IFNULL()funzione di MySQL nella stringa di query. In questo modo:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1

Mi piace la pulizia della tua soluzione. L'ho appena testato, ma sfortunatamente inserisce stringhe vuote invece di NULL quando l'utente non scrive nulla sull'input. È solo una questione di preferenza, ma preferisco NULL invece di stringhe vuote.
Arian Acosta

0

Prova questo.

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null

1
Prima di provare a rispondere a una domanda così vecchia, dovresti prima leggere altre risposte. Può essere già stato risposto.
Il tuo buon senso

0

Sulla base delle altre risposte ma con un po 'più di chiarezza su come utilizzare effettivamente questa soluzione.

Se ad esempio hai una stringa vuota per un valore temporale ma vuoi salvarla come null:

  if($endtime == ""){
    $db->bind(":endtime",$endtime=NULL,PDO::PARAM_STR);
  }else{
    $db->bind("endtime",$endtime);
  }

Si noti che per i valori di tempo si utilizzerà PARAM_STR, poiché i tempi vengono memorizzati come stringhe.


-1

Nel mio caso sto usando:

  • SQLite,

  • istruzioni preparate con segnaposto per gestire un numero sconosciuto di campi,

  • Richiesta AJAX inviata dall'utente in cui tutto è una stringa e non esiste qualcosa come NULLvalore e

  • Ho un disperato bisogno di inserire NULLs in quanto ciò non viola i vincoli della chiave esterna (valore accettabile).

Supponiamo, ora l'utente invia con post: $_POST[field1]con valore value1che può essere la stringa vuota ""o "null"o "NULL".

Per prima cosa faccio la dichiarazione:

$stmt = $this->dbh->prepare("INSERT INTO $table ({$sColumns}) VALUES ({$sValues})");

dov'è {$sColumns}qc field1, field2, ...e {$sValues}sono i miei segnaposto ?, ?, ....

Quindi, raccolgo i miei $_POSTdati relativi ai nomi delle colonne in un array $values e li sostituisco con NULLs:

  for($i = 0; $i < \count($values); $i++)
     if((\strtolower($values[$i]) == 'null') || ($values[$i] == ''))
        $values[$i] = null;

Ora posso eseguire:

$stmt->execute($values);

e tra gli altri bypassare i vincoli della chiave esterna.

Se d'altra parte, una stringa vuota ha più senso, allora devi controllare se quel campo fa parte di una chiave esterna o meno (più complicato).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.