Como insiro valores NULL usando PDO?

105

Estou usando este código e não estou frustrado:

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 eles falham e geram este erro:

Erro fatal : não é possível passar o parâmetro 2 por referência em / opt / ...

Nacho
fonte

Respostas:

138

Estou aprendendo PDO, mas acho que você precisa usar bindValue, nãobindParam

bindParampega uma variável, para referência, e não extrai um valor no momento da chamada bindParam. Eu encontrei isso em um comentário sobre os documentos php:

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

EDIT: PS Você pode ficar tentado a fazer isso, bindValue(':param', null, PDO::PARAM_NULL);mas não funcionou para todos (obrigado, Will Shaver, por reportar.)

JasonWoof
fonte
Não tenho certeza da diferença entre os dois, mas vou investigar algumas. Obrigado, sua resposta foi ótima também.
Nacho,
3
Acho que essa pode ser uma resposta melhor do que a minha (se realmente funcionar)
Joe Phillips,
2
Tive problemas com PDO :: PARAM_NULL no MySql 5.1.53, mas PDO :: PARAM_INT com um valor nulo funcionou muito bem.
Will Shaver
2
Odin: Acho que a parte mais importante é passar os três parâmetros :). na pergunta de ign, ele estava passando PDO :: PARAM_NULL como o valor, em vez de como o tipo (e não passando um tipo)
JasonWoof
1
Para sua informação: na maioria dos casos, você não tem problemas em usar bindValue()over bindParam(); por tudo, não apenas pelo NULLvalor. Não consigo pensar em um único caso em que você precisaria vincular o parâmetro a uma referência de uma variável PHP - mas é isso que bindParam()acontece.
low_rents
48

Ao usar bindParam()você deve passar uma variável, não uma constante. Portanto, antes dessa linha, você precisa criar uma variável e defini-la comonull

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

Você obteria a mesma mensagem de erro se tentasse:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
Joe Phillips
fonte
Você acertou, acabei de perceber que já tinha feito isso antes no meu código, $ null = PDO :: PARAM_NULL; obrigado.
Nacho,
1
É melhor usar bindValue () neste caso, se você for criar espaços reservados de qualquer maneira. bindParam () destina-se originalmente a executar uma consulta e, em seguida, alterar as variáveis ​​e executar novamente sem vincular os parâmetros novamente. bindValue () vincula imediatamente, bindParam () somente na execução.
Hugo Zink,
1
Descobri que nulo deve estar em minúsculas na linha $ myNull = null. $ myNull = NULL NÃO funcionou.
raphael75
27

Ao usar INTEGERcolunas (que podem ser NULL) no MySQL, PDO tem algum (para mim) comportamento inesperado.

Se você usar $stmt->execute(Array), você deve especificar o literal NULLe não pode fornecer NULLpor referência de variável. Portanto, isso não funcionará:

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

Mas isso vai 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

Tentei isso no MySQL 5.5.15 com PHP 5.4.1

ChrisF
fonte
1
$ stmt-> execute (array (': param' =>! empty ($ val)? $ val: null)); Use! Empty porque para string vazia você também deve definir nulo no banco de dados
Shehzad Nizamani
1
@ShehzadNizamani Somente se o tipo da coluna for inteiro, como em seu exemplo, sim. Mas de outra forma se isset()correlaciona melhor para NULL. Uma string vazia também é um valor.
StanE
8

Para quem ainda tem problemas (não é possível passar o parâmetro 2 por referência), defina uma variável com valor nulo, não apenas passe nulo para o PDO:

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

Espero que isto ajude.

Pedro Guglielmo
fonte
6

Eu tive o mesmo problema e encontrei esta solução trabalhando com bindParam:

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

Se você deseja inserir NULLapenas quando valuefor emptyou '', mas insira valuequando estiver disponível.

A) Recebe os dados do formulário usando o método POST e chama a função insert com esses valores.

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

B) Avalia se um campo não foi preenchido pelo usuário e insere NULLse for o 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 exemplo, se o usuário não inserir nada no productNamecampo do formulário, $productNameserá SETmas EMPTY. Portanto, você precisa verificar se é empty(), e se for, insira NULL.

Testado em PHP 5.5.17

Boa sorte,

Arian Acosta
fonte
3
Ou você pode usar a IFNULL()função do MySQL na string de consulta. Assim:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1
Gosto da limpeza sua solução. Eu apenas testei, mas infelizmente ele insere strings vazias em vez de NULL quando o usuário não escreve nada na entrada. É apenas uma questão de preferência, mas prefiro ter NULLs em vez de strings vazias.
Arian Acosta
0

Experimente isso.

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
Hector Teran
fonte
1
Antes de tentar responder a uma pergunta tão antiga, você deve ler as outras respostas primeiro. Pode ser que já tenha sido respondido.
Seu senso comum
0

Com base nas outras respostas, mas com um pouco mais de clareza sobre como realmente usar essa solução.

Se, por exemplo, você tiver uma string vazia para um valor de tempo, mas quiser salvá-la como nula:

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

Observe que para valores de tempo você usaria PARAM_STR, pois os tempos são armazenados como strings.

Vincent
fonte
-1

No meu caso, estou usando:

  • SQLite,

  • preparou declarações com marcadores para lidar com um número desconhecido de campos,

  • Solicitação AJAX enviada pelo usuário onde tudo é uma string e não existe algo como NULLvalor e

  • Eu preciso desesperadamente inserir NULLs, pois isso não viola as restrições de chave estrangeira (valor aceitável).

Suponha que agora o usuário envie com post: $_POST[field1]com valor value1que pode ser a string vazia ""ou "null"ou "NULL".

Primeiro eu faço a declaração:

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

onde {$sColumns}está tudo gosto field1, field2, ...e {$sValues}são meus marcadores de posição ?, ?, ....

Então, eu coleto meus $_POSTdados relacionados aos nomes das colunas em uma matriz $values e substituo por NULLs:

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

Agora posso executar:

$stmt->execute($values);

e entre outras restrições de chave estrangeira de desvio.

Se, por outro lado, uma string vazia faz mais sentido, você deve verificar se esse campo faz parte de uma chave estrangeira ou não (mais complicado).

centuriano
fonte