2017-09-01 140 views
0

我正在撞墙,试图弄清为什么这个PDO准备语句不起作用。我唯一可以总结的是,如果一个变量是空的,那么INSERT失败了,但这是令人困惑的,因为我必须在没有问题的情况下完成了这一千次。用PDO准备好的语句在MySQL中插入空变量

这是我的代码。所有变量都是从POST变量中设置的,所以如果用户没有提供这些数据,其中一些变量可能是空的。

$stmt = $db->prepare("INSERT INTO students 
    (id, classid, userid, firstname, surname, form, gender) 
    VALUES ('', :classid, :userid, :firstname, :surname, :form, :gender)"); 

    $stmt->execute(array(':userid' => $userid, ':classid' => $classid, ':firstname' => $firstname, ':surname' => $surname, ':form' => $form, ':gender' => $gender)); 

是否有某种方法告诉它如果变量为空时插入一个空字段?

编辑:要清楚,这不是一个新的说法。我之前一直使用毫无准备的MySQLi进行INSERT,并且只是将这些代码更新为PDO。

编辑2:我的架构:

id int(11) NO PRI  auto_increment 
encryption int(1) NO    
classid int(11) NO    
googleclassroom varchar(50) NO    
userid varchar(50) NO    
firstname varchar(100) NO    
surname varchar(100) NO    
form varchar(10) NO    
gender varchar(10) NO    
colour_code varchar(10) NO    
col1 varchar(50) NO    
col2 varchar(50) NO    
col3 varchar(50) NO    
col4 varchar(50) NO    
col5 varchar(50) NO    
col6 varchar(50) NO    
col7 varchar(50) NO    
timestamp datetime NO 
+0

你不工作的人是什么?你有什么错误吗?你能记录SQL异常吗? –

+0

用户提供所有值时可以插入值吗? – Billa

+0

这不是插入行。没有错误,但我不确定我是否设置了报告错误。 – Rob

回答

1

你可以用下面的检查:

  1. 允许所有列接受NULL
  2. 如果id是主键,从查询中删除它。你可以将其设置为AUTO_INCREMENT

编辑:

由于id是架构中的主键,你可以不设置'。此外,似乎每个列都不允许接受NULL,并且由于用户未提供该值,所以像$form这样的变量可能未定义或为NULL,因此您的INSERT语句不会执行。

编辑2:

试着找出确切的错误。无论是SQL还是PHP。

您可以通过使用link

+0

我不认为这是解决方案的原因是旧代码中的相同MySQL查询工作正常。添加或删除id字段对这是否有效没有影响。唯一阻止它运行的是如果我绑定一个空变量。 该表肯定接受NULL值,因为之前已经设置了成千上万个具有NULL值的行。 – Rob

+0

你能设置显示错误吗?这里是链接如何设置 http://www.phpreferencebook.com/tips/display-all-php-errors-and-warnings/ –

+0

未定义偏移量:12在... PATH ...在线83 – Rob

1

我想你遇到的问题是由于您的数据获得绑定作为bindParam()设置显示错误。根据PHP文档的。

绑定一个PHP变量到对应的命名或问号 占位符在被用于制备 语句的SQL语句。

所以我喜欢建议使用bindValue()来代替。解释为什么我要回到PHP手册。

不同于PDOStatement对象:: bindValue()时,变量绑定作为参考 并且将仅在该PDOStatement对象::执行时间()是 称为进行评估。

所以我的答案是,

$stmt = $db->prepare("INSERT INTO students 
    (classid, userid, firstname, surname, form, gender) 
    VALUES (:classid, :userid, :firstname, :surname, :form, :gender)"); 

$stmt->bindValue(':classid',$classid);//If this is a must enter or not entered by user then you can use bindParam() 
$stmt->bindValue(':userid',$userid);//This as well if this is a must enter then you can use bindParam() 
if($firstname == "" || $firstname == NULL){ 
$stmt->bindValue(':firstname', NULL, PDO::PARAM_INT);//_NULL seems to give issues 
}else{ 
$stmt->bindParam(':firstname', $firstname); 
} 
$stmt->bindValue(':surname',$surname); 
$stmt->bindValue(':form',$form); 
$stmt->bindValue(':gender',$gender); 

$stmt->execute(); 
+0

谢谢。我试过了,但似乎没有奏效。我在每行之前添加了if is语句,以查看是否有帮助,但导致PHP停止。我需要进一步调查,看看为什么。 – Rob

+0

这可能有助于我认为你已经通过'if ... else' [link](https://stackoverflow.com/questions/13627400/sending-empty-values-with-pdo-results-in-error) – Sand

+0

我更新了答案,请检查并让我知道。您必须切换值。 – Sand

1

罗布,这是不是一个回答您的问题!我阅读你的意见,我只是想告诉你如何正确使用错误报告,准备好的语句和异常处理。

可以结构OOP或程序功能的代码,如果你想。但是这里的结构并不重要。

我的建议是:经常阅读的宇正在使用的功能的文档。尤其是返回的值。这样你就会知道如何正确处理所有可能的容易出错的情况。在PDO的方面,这是一个必不可少的步骤;-)

祝你好运!

<?php 

/* 
* Set error reporting level and display the errors on screen. 
* -------------------------------------------------------------- 
* DON'T DISPLAY ERRORS ON PRODUCTION, DO IT ONLY ON DEVELOPMENT! 
* -------------------------------------------------------------- 
*/ 
error_reporting(E_ALL); 
ini_set('display_errors', 1); 

try { 
    /* 
    * Create a PDO instance as db connection. 
    */ 

    // Create PDO instance. 
    $connection = new PDO(
      'mysql:host=localhost;port=3306;dbname=yourDb;charset=utf8' 
      , 'yourDbUsername' 
      , 'yourDbPassword' 
    ); 

    // Assign driver options. 
    $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    $connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); 
    $connection->setAttribute(PDO::ATTR_PERSISTENT, TRUE); 

    /* 
    * Prepare and validate the sql statement. 
    * 
    * -------------------------------------------------------------------------------- 
    * If the database server cannot successfully prepare the statement, PDO::prepare() 
    * returns FALSE or emits PDOException (depending on error handling settings). 
    * -------------------------------------------------------------------------------- 
    */ 
    $sql = 'INSERT INTO students (
       classid, 
       userid, 
       firstname, 
       surname, 
       form, 
       gender 
      ) VALUES (
       :classid, 
       :userid, 
       :firstname, 
       :surname, 
       :form, 
       :gender 
      )'; 

    $statement = $connection->prepare($sql); 

    if (!$statement) { 
     throw new UnexpectedValueException('The sql statement could not be prepared!'); 
    } 

    /* 
    * Bind the input parameters to the prepared statement. 
    * 
    * ----------------------------------------------------------------------------------- 
    * Unlike PDOStatement::bindValue(), when using PDOStatement::bindParam() the variable 
    * is bound as a reference and will only be evaluated at the time that 
    * PDOStatement::execute() is called. 
    * ----------------------------------------------------------------------------------- 
    */ 

    $bindings = array(
     ':classid' => $classid, 
     ':userid' => $userid, 
     ':firstname' => $firstname, 
     ':surname' => $surname, 
     ':form' => $form, 
     ':gender' => $gender, 
    ); 

    foreach ($bindings as $key => $value) { 
     $bound = $statement->bindValue(
       getInputParameterName($key) 
       , $value 
       , getInputParameterDataType($value) 
     ); 

     if (!$bound) { 
      throw new UnexpectedValueException('An input parameter could not be bound!'); 
     } 
    } 

    /* 
    * Execute the prepared statement. 
    * 
    * ------------------------------------------------------------------ 
    * PDOStatement::execute returns TRUE on success or FALSE on failure. 
    * ------------------------------------------------------------------ 
    */ 
    $executed = $statement->execute(); 

    if (!$executed) { 
     throw new UnexpectedValueException('The prepared statement could not be executed!'); 
    } 

    /* 
    * Get last insert id. 
    */ 
    $lastInsertId = $connection->lastInsertId(); 

    if (!isset($lastInsertId)) { 
     throw new UnexpectedValueException('The last insert id could not be read!'); 
    } 

    /* 
    * Close connection. 
    */ 
    $connection = NULL; 

    /* 
    * Print results. 
    */ 
    echo 'Provided data successfully added with the id: ' . $lastInsertId; 
} catch (PDOException $pdoException) { 
    echo $pdoException->getMessage(); 
    exit(); 
} catch (Exception $exception) { 
    echo $exception->getMessage(); 
    exit(); 
} 

/** 
* Get the name of an input parameter by its key in the bindings array. 
* 
* @param int|string $key The key of the input parameter in the bindings array. 
* @return int|string The name of the input parameter. 
*/ 
function getInputParameterName($key) { 
    return is_int($key) ? ($key + 1) : (':' . ltrim($key, ':')); 
} 

/** 
* Get the PDO::PARAM_* constant, e.g the data type of an input parameter, by its value. 
* 
* @param mixed $value Value of the input parameter. 
* @return int The PDO::PARAM_* constant. 
*/ 
function getInputParameterDataType($value) { 
    $dataType = PDO::PARAM_STR; 
    if (is_int($value)) { 
     $dataType = PDO::PARAM_INT; 
    } elseif (is_bool($value)) { 
     $dataType = PDO::PARAM_BOOL; 
    } 
    return $dataType; 
} 
0

谢谢你的所有意见和答案。几个不同的用户建议允许NULL值; @sand建议我将这些列的默认值设置为NULL。它的工作

我仍然感到困惑,如何这已经愉快地工作了几个月(使用措手不及MySQLi的说法),但拒绝接受来自PDO声明这些插入。

无论如何,答案(全部归功于@Sand,@Anshuman和@劳伦斯)是将默认列值设置为NULL,那么它并不在乎变量是否为空。