Wie füge ich NULL-Werte mit PDO ein?

105

Ich benutze diesen Code und bin nicht frustriert:

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, '', Alle scheitern und werfen diesen Fehler:

Schwerwiegender Fehler : Parameter 2 kann nicht als Referenz in / opt / ... übergeben werden.

Nacho
quelle

Antworten:

138

Ich lerne gerade PDO, aber ich denke, Sie müssen verwenden bindValue, nichtbindParam

bindParamNimmt eine Variable als Referenz und zieht zum Zeitpunkt des Aufrufs keinen Wert ein bindParam. Ich fand dies in einem Kommentar zu den PHP-Dokumenten:

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

EDIT: PS Sie könnten versucht sein, dies zu tun, bindValue(':param', null, PDO::PARAM_NULL);aber es hat nicht bei allen funktioniert (danke Will Shaver für die Berichterstattung.)

JasonWoof
quelle
Ich bin mir nicht sicher, welchen Unterschied diese beiden haben, aber ich werde einige untersuchen. Danke, deine Antwort war auch großartig.
Nacho
3
Ich denke, dies könnte eine bessere Antwort sein als meine (wenn es tatsächlich funktioniert)
Joe Phillips
2
Ich hatte Probleme mit PDO :: PARAM_NULL unter MySql 5.1.53, aber PDO :: PARAM_INT mit einem Nullwert funktionierte hervorragend.
Will Shaver
2
Odin: Ich denke, der wichtigste Teil ist, alle drei Parameter zu übergeben :). In Igns Frage übergab er PDO :: PARAM_NULL als Wert anstatt als Typ (und überhaupt keinen Typ).
JasonWoof
1
Zu Ihrer Information: In den meisten Fällen ist es völlig in Ordnung, bindValue()Over zu verwenden bindParam(). für alles, nicht nur für den NULLWert. Ich kann mir keinen einzigen Fall vorstellen, in dem Sie den Parameter an eine Referenz einer PHP-Variablen binden müssten - aber genau das bindParam()tut es.
low_rents
48

Bei der Verwendung bindParam()müssen Sie eine Variable übergeben, keine Konstante. Vor dieser Zeile müssen Sie also eine Variable erstellen und auf setzennull

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

Sie würden die gleiche Fehlermeldung erhalten, wenn Sie versuchen würden:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
Joe Phillips
quelle
Sie haben das richtig verstanden, ich habe gerade festgestellt, dass ich es zuvor in meinem Code getan habe: $ null = PDO :: PARAM_NULL; Vielen Dank.
Nacho
1
In diesem Fall ist es besser, bindValue () zu verwenden, wenn Sie ohnehin Platzhalter erstellen möchten. bindParam () soll ursprünglich eine Abfrage ausführen, dann die Variablen ändern und erneut ausführen, ohne die Parameter erneut zu binden. bindValue () bindet sofort, bindParam () nur bei Ausführung.
Hugo Zink
1
Ich habe festgestellt, dass null in der Zeile $ myNull = null klein geschrieben sein muss. $ myNull = NULL hat NICHT funktioniert.
Raphael75
27

Bei Verwendung von INTEGERSpalten (das kann seinNULL ) in MySQL hat PDO ein (für mich) unerwartetes Verhalten.

Wenn Sie verwenden $stmt->execute(Array), müssen Sie das Literal angeben NULLund können nicht NULLdurch Variablenreferenz angeben . Das wird also nicht funktionieren:

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

Aber das wird funktionieren:

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

Versuchte dies unter MySQL 5.5.15 mit PHP 5.4.1

ChrisF
quelle
1
$ stmt-> execute (array (': param' =>! empty ($ val)? $ val: null)); Verwenden Sie! Leer, weil Sie für leere Zeichenfolge auch null in der Datenbank setzen möchten
Shehzad Nizamani
1
@ShehzadNizamani Nur wenn der Spaltentyp eine Ganzzahl ist, wie in seinem Beispiel, ja. Aber sonst isset()korreliert besser zu NULL. Eine leere Zeichenfolge ist ebenfalls ein Wert.
StanE
8

Definieren Sie für diejenigen, die immer noch Probleme haben (Parameter 2 kann nicht als Referenz übergeben werden), eine Variable mit dem Wert null und nicht nur null an PDO:

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

Hoffe das hilft.

Pedro Guglielmo
quelle
6

Ich hatte das gleiche Problem und fand diese Lösung mit bindParam:

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

Wenn Sie NULLnur einfügen möchten, wenn das valueist emptyoder '', aber das einfügen, valuewenn es verfügbar ist.

A) Empfängt die Formulardaten mit der POST-Methode und ruft die Funktion insert mit diesen Werten auf.

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

B) Wertet aus, ob ein Feld vom Benutzer nicht ausgefüllt wurde, und fügt ein, NULLob dies der Fall ist.

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

Wenn der Benutzer beispielsweise nichts in das productNameFeld des Formulars $productNameeingibt, ist dies SETjedoch der Fall EMPTY. Sie müssen also überprüfen, ob dies der Fall ist empty(), und dann einfügen NULL.

Getestet auf PHP 5.5.17

Viel Glück,

Arian Acosta
quelle
3
Oder Sie können die MySQL- IFNULL()Funktion in der Abfragezeichenfolge verwenden. So:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1
Ich mag die Sauberkeit Ihrer Lösung. Ich habe es gerade getestet, aber leider fügt es leere Zeichenfolgen anstelle von NULL ein, wenn der Benutzer nichts in die Eingabe schreibt. Es ist nur eine Frage der Präferenz, aber ich habe lieber NULL-Werte als leere Zeichenfolgen.
Arian Acosta
0

Versuche dies.

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
hector teran
quelle
1
Bevor Sie versuchen, eine so alte Frage zu beantworten, sollten Sie zuerst andere Antworten lesen. Möglicherweise wurde es bereits beantwortet.
Ihr gesunder Menschenverstand
0

Basierend auf den anderen Antworten, aber mit etwas mehr Klarheit darüber, wie diese Lösung tatsächlich verwendet wird.

Wenn Sie beispielsweise eine leere Zeichenfolge für einen Zeitwert haben, diese aber als Null speichern möchten:

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

Beachten Sie, dass Sie für Zeitwerte PARAM_STR verwenden würden, da die Zeiten als Zeichenfolgen gespeichert werden.

Vincent
quelle
-1

In meinem Fall verwende ich:

  • SQLite,

  • vorbereitete Anweisungen mit Platzhaltern zur Behandlung einer unbekannten Anzahl von Feldern,

  • Vom Benutzer gesendete AJAX-Anfrage, bei der alles eine Zeichenfolge ist und es keinen NULLWert und gibt

  • Ich muss dringend NULLs einfügen, da dies nicht gegen Fremdschlüsseleinschränkungen verstößt (akzeptabler Wert).

Angenommen, der Benutzer sendet jetzt mit post: $_POST[field1]mit einem Wert, value1der die leere Zeichenfolge ""oder "null"oder sein kann"NULL" .

Zuerst mache ich die Aussage:

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

wo {$sColumns}ist etw wie field1, field2, ...und{$sValues} sind meine Platzhalter??, ?, ... .

Dann sammle ich meine $_POSTDaten zu den Spaltennamen in einem Array $values und ersetze sie durch NULLs:

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

Jetzt kann ich ausführen:

$stmt->execute($values);

und unter anderem Fremdschlüsseleinschränkungen umgehen.

Wenn andererseits eine leere Zeichenfolge sinnvoller ist, müssen Sie prüfen, ob dieses Feld Teil eines Fremdschlüssels ist oder nicht (komplizierter).

Centurian
quelle