PDO使用MySQL的NOW()

时间:2013-12-20 12:01:21

标签: php mysql sql pdo

我如何在PDO预处理语句中使用MySQL的NOW(),或者我将如何解决使用它,同时记住可能Apache服务器和数据库服务器可能有轻微的当前时间不匹配(几秒钟),或者在极少数情况下可能会分开时区?

我的代码中有以下功能:

try {
    $dbh->insert("users", array(
        "email" => $email,
        "password" => $password,
        "salt" => $salt,
        "ingame" => $ingame,
        "kiosk" => $kiosk
    ));
} catch (PDOException $ex) {
    error($ex);
}

哪个电话:

/**
 * Inserts data into a table. Data must be given in key-value pairs.
 * 
 * Example: $dbh->insert("table", array(
 *                                  "data1" => $data1,
 *                                  "data2" => $data2
 *                                  );
 * 
 * @param type $table   The table to insert to
 * @param type $keyvaluepairs   The key-value pairs.
 * @return type The statement that this query produced.
 */
public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        $sql .= "`${key}`, ";
        $values_sql .= "?, ";
        $values[] = $value;
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}

哪个电话:

//TODO update documentation to show it also handles associative arrays with bindvalue
/**
 * Can be called to create a query. Use either unnamed or named placeholders for the prepared statements.
 * 
 * Example: $dbh->query("INSERT INTO table (data1, data2) VALUES(?, ?)", array($data1, $data2));
 * 
 * @param type $query   The input query, including unnamed or named placeholders
 * @param type $values  The input values. If it's not an array, then it will be an one-element array
 * @return type The statement constructed by this query
 */
public function query($query, $values = array()) {
    if (!is_array($values)) {
        $values = array($values);
    }
    $statement = $this->dbh->prepare($query);
    $statement->setFetchMode(PDO::FETCH_OBJ);
    $i = 1;
    if (is_assoc($values)) {
        foreach ($values as $key => $value) {
            $statement->bindValue($key, $value);
        }
    }
    else {
        foreach ($values as $value) {
            $statement->bindValue($i++, $value);
        }
    }
    $statement->execute();
    return $statement;
}

我有这个功能:

function is_assoc($array) {
    return (bool)count(array_filter(array_keys($array), 'is_string'));
}

所以这里的交易是我不能对插入使用自定义MySQL查询,因为我为了方便而封装了这些,但我仍然希望能够插入NOW() 没有使用TIMESTAMP / CURRENT_TIMESTAMP()

我希望您理解这个问题需要一个解释性的答案,因为我已经阅读了“正常”答案,并表明它们不能满足我的需求。

更新:我已将const SQL_NOW = 1;添加到DBH课程,但现在我想将insert修改为以下内容:

public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        if ($value == SELF::SQL_NOW) {
            $sql .= "NOW(), ";
        }
        else {
            $sql .= "`${key}`, ";
            $values_sql .= "?, ";
            $values[] = $value;
        }
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}

这可能是一个合适的解决方案,然而我不能将1用作SQL_NOW值,因为如果我想插入一个整数{{},它就会失败1}}。如果我使用这个解决方案,1会有什么价值?甚至可以给它没有价值

2 个答案:

答案 0 :(得分:2)

很棒的问题!

这是一个很好的例子,清楚地说明为什么所有这些insert(), update()和所有其他用来替代SQL的东西都是错误的设计

NOW()不是您将面临的唯一问题。仅仅因为 SQL并不像乍一看似乎是一种愚蠢的语言。它是故意发明的。几十年来,它的可靠性得到了证实。这意味着在学习PHP时,将整个SQL编写为练习并不容易。

因此,您可以做的最好的事情是保持SQL原样。

你真正需要的是一个或两个辅助功能。自动执行重复性任务。就这些。虽然SQL必须保持原样。这将让你使用它的所有功能,包括使用函数,带参数的函数(!),查询修饰符,如'INSERT IGNORE'或扩展语法,如JOINS。

如果您使用PDO,它并不是那么简单但可行。

但是,唯一合适的解决方案是为SET语句使用特殊类型的占位符

$data = array(
        "email"    => $email,
        "password" => $password,
        "salt"     => $salt,
        "ingame"   => $ingame,
        "kiosk"    => $kiosk,
);
$dbh->query("INSERT INTO ?n SET reg = NOW(), ?u","users", $data);

只需一条线来解决所有混乱以及许多很多其他问题 只需一个query()方法即可运行您想要的任何查询,甚至REPLACE INTO

更新

看看你在做什么!

您正在计划您的课程简化事情。但目前你正在变得越来越复杂。最后,你将拥有一个笨重的巨人,即使是它的创造者和其他人也几乎无法理解的众多例外的语法不一致。 仍然不允许您运行某些查询。

请在为时已晚之前重新考虑您的设计。

答案 1 :(得分:-1)

如果您传递一个包含所需的所有column => SQLfunction值的附加参数,您可以编写一个执行此操作的包装器。

我的样子如下:

var f = function g() {
    console.log("test");
};

g(); // ReferenceError: g is not defined

像这样使用:

function pInsertFunc($action, $table, $values, $sqlfunctions)
{

    global $pdb;

    // There's no way to pass an SQL function like "NOW()" as a PDO parameter,
    // so this function builds the query string with those functions.  $values
    // and $sqlfunctions should be key => value arrays, with column names
    // as keys.  The $values values will be passed in as parameters, and the
    // $sqlfunction values will be made part of the query string.

    $value_columns = array_keys($values);
    $sqlfunc_columns = array_keys($sqlfunctions);
    $columns = array_merge($value_columns, $sqlfunc_columns);

    // Only $values become ':paramname' PDO parameters.
    $value_parameters = array_map(function($col) {return (':' . $col);}, $value_columns);
    // SQL functions go straight in as strings.
    $sqlfunc_parameters = array_values($sqlfunctions);
    $parameters = array_merge($value_parameters, $sqlfunc_parameters);

    $column_list = join(', ', $columns);
    $parameter_list = join(', ', $parameters);

    $query = "$action $table ($column_list) VALUES ($parameter_list)";

    $stmt = $pdb->prepare($query);
    $stmt->execute($values);

}

结果的查询字符串如下所示:

$values = array(
    'ID' => NULL,
    'name' => $username,
    'address' => $address,
);

$sqlfuncs = array(
    'date' => 'NOW()',
);

pInsertFunc("INSERT INTO", "addresses", $values, $sqlfuncs);