¿Cómo inserto valores NULL usando PDO?

105

Estoy usando este código y estoy más allá de la frustración:

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, '', todos fallan y arrojan este error:

Error fatal : no se puede pasar el parámetro 2 por referencia en / opt / ...

Nacho
fuente

Respuestas:

138

Estoy aprendiendo PDO, pero creo que debes usar bindValue, nobindParam

bindParamtoma una variable, para hacer referencia, y no extrae un valor en el momento de la llamada bindParam. Encontré esto en un comentario en los documentos php:

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

EDITAR: PD: Puede tener la tentación de hacer esto, bindValue(':param', null, PDO::PARAM_NULL);pero no funcionó para todos (gracias Will Shaver por informar).

Jason Woof
fuente
No estoy seguro de la diferencia entre esos dos, pero investigaré algunos. Gracias, tu respuesta también fue genial.
Nacho
3
Creo que esta podría ser una mejor respuesta que la mía (si es que funciona)
Joe Phillips
2
Tuve problemas con PDO :: PARAM_NULL en MySql 5.1.53, pero PDO :: PARAM_INT con un valor nulo funcionó muy bien.
Will Shaver
2
Odin: Creo que la parte más importante es pasar los tres parámetros :). en la pregunta de ign, estaba pasando PDO :: PARAM_NULL como el valor, en lugar de como el tipo (y no pasando un tipo en absoluto)
JasonWoof
1
FYI: en la mayoría de los casos, está completamente de acuerdo con usar bindValue()over bindParam(); por todo, no solo por el NULLvalor. No puedo pensar en un solo caso en el que necesite vincular el parámetro a una referencia de una variable de PHP, pero eso es lo que bindParam()hace.
low_rents
48

Al usarlo bindParam(), debe pasar una variable, no una constante. Entonces, antes de esa línea, debe crear una variable y establecerla ennull

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

Obtendría el mismo mensaje de error si intentara:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
Joe Phillips
fuente
Tienes razón, me acabo de dar cuenta de que lo había hecho antes en mi código, $ null = PDO :: PARAM_NULL; Gracias.
Nacho
1
Es mejor usar bindValue () en este caso, si va a hacer marcadores de posición de todos modos. bindParam () originalmente estaba destinado a ejecutar una consulta, y luego cambiar las variables y volver a ejecutar sin vincular los parámetros nuevamente. bindValue () enlaza inmediatamente, bindParam () solo al ejecutar.
Hugo Zink
1
Encontré que null debe estar en minúsculas en la línea $ myNull = null. $ myNull = NULL NO funcionó.
raphael75
27

Cuando se usan INTEGERcolumnas (que pueden ser NULL) en MySQL, PDO tiene un comportamiento inesperado (para mí).

Si usa $stmt->execute(Array), debe especificar el literal NULLy no puede dar NULLpor referencia de variable. Entonces esto no funcionará:

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

Pero esto funcionará:

// $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

Probé esto en MySQL 5.5.15 con PHP 5.4.1

ChrisF
fuente
1
$ stmt-> execute (array (': param' =>! empty ($ val)? $ val: null)); Use! Empty porque para una cadena vacía también querría establecer un valor nulo en la base de datos
Shehzad Nizamani
1
@ShehzadNizamani Solo si el tipo de columna es entero, como en su ejemplo, sí. Pero por lo demás se isset()correlaciona mejor con NULL. Una cadena vacía también es un valor.
StanE
8

Para aquellos que todavía tienen problemas (No se puede pasar el parámetro 2 por referencia), defina una variable con valor nulo, no solo pase nulo a PDO:

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

Espero que esto ayude.

Pedro Guglielmo
fuente
6

Tuve el mismo problema y encontré esta solución trabajando con bindParam:

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

Si desea insertar NULLsolo cuando valuees emptyo '', pero inserte valuecuando esté disponible.

A) Recibe los datos del formulario usando el método POST y llama a la función insert con esos valores.

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

B) Evalúa si el usuario no llenó un campo e inserta NULLsi ese es el caso.

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();      
}

Por ejemplo, si el usuario no ingresa nada en el productNamecampo del formulario, $productNameserá SETpero EMPTY. Por lo tanto, debe verificar si lo es empty(), y si lo es, insertar NULL.

Probado en PHP 5.5.17

Buena suerte,

Arian Acosta
fuente
3
O puede usar la IFNULL()función de MySQL en la cadena de consulta. Así:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1
Me gusta la limpieza tu solución. Lo acabo de probar, pero desafortunadamente inserta cadenas vacías en lugar de NULL cuando el usuario no escribe nada en la entrada. Es solo una cuestión de preferencia, pero prefiero tener NULL en lugar de cadenas vacías.
Arian Acosta
0

Prueba esto.

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
hector terán
fuente
1
Antes de intentar responder a una pregunta tan antigua, primero debe leer otras respuestas. Puede ser que ya haya sido respondido.
Your Common Sense
0

Basado en las otras respuestas pero con un poco más de claridad sobre cómo usar esta solución.

Si, por ejemplo, tiene una cadena vacía para un valor de tiempo pero desea guardarlo como nulo:

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

Tenga en cuenta que para los valores de tiempo usaría PARAM_STR, ya que los tiempos se almacenan como cadenas.

Vincent
fuente
-1

En mi caso estoy usando:

  • SQLite,

  • declaraciones preparadas con marcadores de posición para manejar un número desconocido de campos,

  • Solicitud AJAX enviada por el usuario donde todo es una cadena y no existe tal cosa como NULLvalor y

  • Necesito desesperadamente insertar NULLs, ya que eso no viola las restricciones de clave externa (valor aceptable).

Supongamos que ahora el usuario envía con publicación: $_POST[field1]con un valor value1que puede ser la cadena vacía ""o "null"o "NULL".

Primero hago la declaración:

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

¿Dónde {$sColumns}está algo como field1, field2, ...y {$sValues}son mis marcadores de posición??, ?, ... .

Luego, recopilo mis $_POSTdatos relacionados con los nombres de las columnas en una matriz $values y los reemplazo con NULLs:

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

Ahora, puedo ejecutar:

$stmt->execute($values);

y entre otras restricciones de clave externa de bypass.

Si, por otro lado, una cadena vacía tiene más sentido, entonces debe verificar si ese campo es parte de una clave externa o no (más complicado).

centurian
fuente