ฉันจะแทรกค่า NULL โดยใช้ PDO ได้อย่างไร


105

ฉันใช้รหัสนี้และฉันก็ไม่รู้สึกหงุดหงิด:

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, '', ทั้งหมดล้มเหลวและโยนข้อผิดพลาดนี้:

ข้อผิดพลาดร้ายแรง : ไม่สามารถส่งผ่านพารามิเตอร์ 2 โดยอ้างอิงใน / opt / ...

คำตอบ:


138

ฉันแค่เรียนรู้ PDO แต่ฉันคิดว่าคุณต้องใช้bindValueไม่ใช่bindParam

bindParambindParamใช้เวลาตัวแปรอ้างอิงและไม่ดึงค่าในช่วงเวลาของการโทร ฉันพบสิ่งนี้ในความคิดเห็นบนเอกสาร php:

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

แก้ไข: ป.ล. คุณอาจถูกล่อลวงให้ทำสิ่งนี้bindValue(':param', null, PDO::PARAM_NULL);แต่ก็ไม่ได้ผลสำหรับทุกคน (ขอบคุณ Will Shaver สำหรับการรายงาน)


ฉันไม่แน่ใจความแตกต่างระหว่างสองคนนี้ แต่ฉันจะตรวจสอบบางส่วน ขอบคุณคำตอบของคุณก็ดีเช่นกัน
Nacho

3
ฉันคิดว่านี่อาจเป็นคำตอบที่ดีกว่าของฉัน (ถ้ามันได้ผลจริง)
Joe Phillips

2
ฉันมีปัญหากับ PDO :: PARAM_NULL บน MySql 5.1.53 แต่ PDO :: PARAM_INT ที่มีค่า null ใช้งานได้ดี
Will Shaver

2
Odin: ฉันคิดว่าส่วนที่สำคัญที่สุดคือการส่งผ่านพารามิเตอร์ทั้งสามตัว :) ในคำถามของ ign เขาส่ง PDO :: PARAM_NULL เป็นค่าแทนที่จะเป็นประเภท (และไม่ผ่านประเภทเลย)
JasonWoof

1
FYI: ในกรณีส่วนใหญ่คุณจะสมบูรณ์ดีกับการใช้bindValue()มากกว่าbindParam(); สำหรับทุกสิ่งไม่ใช่เพื่อความNULLคุ้มค่า ฉันไม่สามารถนึกถึงกรณีเดียวที่คุณจะต้องผูกพารามิเตอร์กับการอ้างอิงของตัวแปร PHP - แต่นั่นคือสิ่งที่bindParam()ทำ
low_rents

49

เมื่อใช้bindParam()คุณต้องส่งผ่านตัวแปรไม่ใช่ค่าคงที่ ดังนั้นก่อนบรรทัดนั้นคุณต้องสร้างตัวแปรและตั้งค่าเป็นnull

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

คุณจะได้รับข้อความแสดงข้อผิดพลาดเดียวกันหากคุณลอง:

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

คุณเข้าใจถูกแล้วฉันเพิ่งรู้ว่าฉันเคยทำมาก่อนแล้วในโค้ดของฉัน $ null = PDO :: PARAM_NULL; ขอบคุณ.
Nacho

1
จะดีกว่าถ้าใช้ bindValue () ในกรณีนี้ถ้าคุณจะสร้างตัวยึดตำแหน่ง bindParam () เดิมมีไว้เพื่อดำเนินการสืบค้นจากนั้นเปลี่ยนตัวแปรและดำเนินการใหม่โดยไม่ผูกพารามิเตอร์อีกครั้ง bindValue () ผูกทันที bindParam () เมื่อรันเท่านั้น
Hugo Zink

1
ฉันพบว่า null ต้องเป็นตัวพิมพ์เล็กในบรรทัด $ myNull = null $ myNull = NULL ไม่ทำงาน
raphael75

28

เมื่อใช้INTEGERคอลัมน์ (ที่สามารถเป็นได้NULL) ใน MySQL PDO มีพฤติกรรมที่ไม่คาดคิด (สำหรับฉัน)

หากคุณใช้$stmt->execute(Array)คุณต้องระบุลิเทอรัลNULLและไม่สามารถให้NULLโดยการอ้างอิงตัวแปร ดังนั้นจะใช้ไม่ได้:

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

แต่จะได้ผล:

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

ลองใช้กับ MySQL 5.5.15 ด้วย PHP 5.4.1


1
$ stmt-> ดำเนินการ (array (': param' =>! empty ($ val)? $ val: null)); ใช้! ว่างเพราะสำหรับสตริงว่างคุณต้องการตั้งค่า null ในฐานข้อมูลด้วย
Shehzad Nizamani

1
@ShehzadNizamani เฉพาะในกรณีที่ประเภทคอลัมน์เป็นจำนวนเต็มเช่นในตัวอย่างของเขาใช่ แต่อย่างอื่นมีความสัมพันธ์ที่ดีขึ้นเพื่อisset() NULLสตริงว่างก็เป็นค่าเช่นกัน
StanE

8

สำหรับผู้ที่ยังคงมีปัญหา (ไม่สามารถส่งผ่านพารามิเตอร์ 2 โดยการอ้างอิง) ให้กำหนดตัวแปรด้วยค่า null ไม่ใช่แค่ส่ง null ไปยัง PDO:

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

หวังว่านี่จะช่วยได้



3

หากคุณต้องการแทรกNULLเฉพาะเมื่อvalueมีemptyหรือ''แต่ให้แทรกvalueเมื่อพร้อมใช้งาน

A) รับข้อมูลแบบฟอร์มโดยใช้เมธอด POST และเรียกใช้ฟังก์ชันแทรกด้วยค่าเหล่านั้น

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

B) ประเมินว่าผู้ใช้ไม่กรอกฟิลด์หรือไม่และแทรกNULLหากเป็นเช่นนั้น

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

ตัวอย่างเช่นหากผู้ใช้ไม่ได้อะไรไม่ได้ป้อนข้อมูลในproductNameด้านของรูปแบบแล้ว$productNameจะมีแต่SET EMPTYดังนั้นคุณต้องตรวจสอบว่ามันเป็นและถ้าเป็นแล้วแทรกempty()NULL

ทดสอบกับ PHP 5.5.17

โชคดี,


3
หรือคุณสามารถใช้IFNULL()ฟังก์ชันของ MySQL ในสตริงการสืบค้น แบบนี้:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1

ฉันชอบความสะอาดของน้ำยาของคุณ ฉันเพิ่งทดสอบ แต่น่าเสียดายที่มันแทรกสตริงว่างแทน NULL เมื่อผู้ใช้ไม่ได้เขียนอะไรลงในอินพุต มันเป็นเรื่องของความชอบ แต่ฉันต้องการ NULL แทนที่จะเป็นสตริงว่างเปล่า
Arian Acosta


0

อ้างอิงจากคำตอบอื่น ๆ แต่มีความชัดเจนมากขึ้นเล็กน้อยเกี่ยวกับวิธีใช้โซลูชันนี้จริง

ตัวอย่างเช่นคุณมีสตริงว่างสำหรับค่าเวลา แต่คุณต้องการบันทึกเป็นค่าว่าง:

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

โปรดสังเกตว่าสำหรับค่าเวลาคุณจะใช้ PARAM_STR เนื่องจากเวลาจะถูกเก็บไว้เป็นสตริง


-1

ในกรณีของฉันฉันใช้:

  • SQLite,

  • เตรียมงบพร้อมตัวยึดเพื่อจัดการกับจำนวนฟิลด์ที่ไม่รู้จัก

  • คำขอ AJAX ที่ส่งโดยผู้ใช้โดยที่ทุกอย่างเป็นสตริงและไม่มีสิ่งนั้นเช่นNULLค่าและ

  • ฉันจำเป็นต้องใส่NULLs เป็นอย่างยิ่งเนื่องจากไม่ละเมิดข้อ จำกัด ของคีย์ต่างประเทศ (ค่าที่ยอมรับได้)

สมมติว่าตอนนี้ผู้ใช้ส่งกับโพสต์: $_POST[field1]มีค่าvalue1ซึ่งอาจจะเป็นสตริงที่ว่างเปล่า""หรือหรือ"null""NULL"

ก่อนอื่นฉันสร้างคำสั่ง:

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

ที่{$sColumns}เป็นเหมือนฏfield1, field2, ...และมีตัวยึดตำแหน่งของฉัน{$sValues}?, ?, ...

จากนั้นฉันรวบรวม$_POSTข้อมูลของฉันที่เกี่ยวข้องกับชื่อคอลัมน์ในอาร์เรย์$values และแทนที่ด้วยNULLs:

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

ตอนนี้ฉันสามารถดำเนินการ:

$stmt->execute($values);

และข้ามข้อ จำกัด คีย์ต่างประเทศอื่น ๆ

หากในทางกลับกันสตริงว่างจะมีความหมายมากกว่านั้นคุณต้องตรวจสอบว่าฟิลด์นั้นเป็นส่วนหนึ่งของคีย์ต่างประเทศหรือไม่ (ซับซ้อนกว่า)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.