PHP MySQL - How to insert default value in a prepared statement

a 夏天 提交于 2019-12-07 18:08:29

问题


Let's say I have a prepared statement that looks like this:

$insertSql = "";
$insertSql .= "INSERT INTO table";
$insertSql .= "(tag,month_interval,month_interval_lastupdated,date_due,date_due_lastupdated,date_completion,date_completion_lastupdated,";
$insertSql .= "activeNotification,date_lastmodified) ";
$insertSql .= "VALUES (?,?,NOW(),?,NOW(),?,NOW(),?,NOW())";

But sometimes some of those question marks would not be set.

Is there a keyword I can substitute in the prepared statement that tells MySQL to insert the default?

Something like:

if($stmt = $mysqli->prepare($insertSql)) {
   if(!isset($tag)) {
      // code to find first question mark and replace w/ default value
      }
      $stmt->bind_param('sisss',$tag,$month_interval,$date_due,$date_completion);
      $stmt->execute();
}

The default value for the date fields is '1000-01-01 00:00:00' and the default value for month_interval is 0, the rest of the fields have a default of NULL.


回答1:


Your question addresses an interesting subject, in my opinion.

By a rapid search, I don't have found any predefined solution, but I will continue search in the next days.

I have elaborate a solution, but it is a bit twisted and not totally clean.

First of all, I redefine the query with placeholders:

$query = "
    INSERT INTO table
                (
                    tag,
                    month_interval,
                    month_interval_lastupdated,
                    date_due,
                    date_due_lastupdated,
                    date_completion,
                    date_completion_lastupdated,
                    activeNotification,
                    date_lastmodified
                )
         VALUES (<tag>,<month_interval>,NOW(),<date_due>,NOW(),<date_completion>,NOW(),<activeNotification>,NOW())
";

In this example, I use <> to surround placeholder, but you can choose your preferred placeholder, making sure that they do not confuse with others elements of the query.

Then, I init an associative array with keys as placeholders names and values to be bind, and a variable ($types) with the complete set of bind types:

$values = array( 'tag'=>$tag, 'month_interval'=>$month_interval, 'date_due'=>$date_due, 'date_completion'=>$date_completion, 'activeNotification'=>$activeNotification );
$types = 'sisss';

Then, the most important line. I init an array in this strange way:

$bind = array( Null, '' );

The index 0 is set to Null, because is reserved for the stmt object (created below); the index 1 is an empty string that will be filled with necessary bind types.

Now I perform a foreach loop through all elements of array $values:

$i = 0;
foreach( $values as $key => $val )
{
    if( is_null( $val ) )
    {
        $query = str_replace( '<'.$key.'>', 'DEFAULT', $query );
    }
    else
    {
        $query    = str_replace( '<'.$key.'>', '?', $query );
        $bind[1] .= $types[$i];
        $bind[]   = &$val;
    }
    $i++;
}

In that loop, if the value is null I replace the corresponding query's placeholder with mySQL keyword DEFAULT. Otherwise, I replace placeholder with a ?, I add the corresponding $types substring to $bind[1], and I append the value (by reference) to $bind array.

At this point, the real query is ready to go, and I can prepare it:

$stmt = $db->prepare( $query ) or die( $stmt->error );

and, if there are not default values (count($bind)>2), I can bind it:

if( count($bind)>2 )
{
    $bind[0] = $stmt;
    call_user_func_array( 'mysqli_stmt_bind_param', $bind );
}

As said before, I set $bind[0] to stmt object returned by ->prepare, then I use call_user_func_array to perform mysqli_stmt_bind_param. I can't directly call ->bind_param because I have a variable arguments number.

At the end of this eccentric process, finally I can execute the query:

$stmt->execute() or die( $stmt->error );

I have tested this code, and it works.

The main problem reside in the is_null( $val ): using an array, I can't use isset as test, because every element of an array is even set. The code works if all the field with placeholder that allows Null value has Null ad default value.




回答2:


I had the same issue, so I adapted this answer https://stackoverflow.com/a/13867665/1251063 to php prepared statement:

if(!($stmt = $this->conn->prepare("INSERT INTO mytable (myfield) VALUES (IFNULL(?,DEFAULT(myfield)))"))){
    throw new Exception("Prepare failed: (" . $this->conn->errno . ") " . $this->conn->error);
}

if(!($stmt->bind_param("s",$myfield))) { //$myfield is a variable that can be null, if so the default value for such field will be inserted
    throw new Exception("Bind_param failed: (" . $this->conn->errno . ") " . $this->conn->error);
}

if(!$stmt->execute()) {
    throw new Exception("Execute failed: (" . $stmt->errno . ") " . $stmt->error);
}



回答3:


Just a thought, if you have a condition when you do not know all the values, you should prepare the statement to do not even add those values.

Also in some cases (for example on autoincrement fields) you can just insert a NULL which will trigger the default value to be inserted, BUT do be carefull if the field definition does allow NULL's inserting a NULL will insert a NULL.



来源:https://stackoverflow.com/questions/35517021/php-mysql-how-to-insert-default-value-in-a-prepared-statement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!