【问题标题】:MySQL syntax error when using question mark placeholders in prepared statement在准备好的语句中使用问号占位符时 MySQL 语法错误
【发布时间】:2018-06-04 17:15:56
【问题描述】:

尝试了我能想到的所有方法,但我已将范围缩小到“?”占位符。

我试过替换“?”带有随机文本的占位符,一切正常(当然除了它不断覆盖同一行)。

我得到的错误:

您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在 '?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 附近使用的正确语法 重复密钥更新 第 2 行的产品

这是我的代码(我会提供更多,但除了这个错误之外,它一切正常,如果我删除“?”占位符,那么除了值不是动态的之外,所有的都可以正常工作,但请询问您是否怀疑问题在别处):

    // Create MySQL connection to ds_signifyd_api
    $mysqli = mysqli_connect( $db_server_name, $db_username, $db_password, $db_name );
    // Check connection
    if ($mysqli->connect_error) {
        exit( $mysqliFailedBody );
    }

    $mainProdQueryStmt = "INSERT INTO products (`product_id`, `title`, `body_html`, `vendor`, `product_type`, `created_at`, `handle`, `updated_at`, `published_at`, `template_suffix`, `published_scope`, `tags`) 
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
        ON DUPLICATE KEY UPDATE 
            product_id = VALUES(product_id), 
            title = VALUES(title), 
            body_html = VALUES(body_html),
            vendor = VALUES(vendor), 
            product_type = VALUES(product_type), 
            created_at = VALUES(created_at), 
            handle = VALUES(handle), 
            updated_at = VALUES(updated_at), 
            published_at = VALUES(published_at), 
            template_suffix = VALUES(template_suffix), 
            published_scope = VALUES(published_scope), 
            tags = VALUES(tags)";

        $product_id = $product_title = $body_html = $vendor = $product_type = $created_at = $handle = $updated_at = $published_at = $template_suffix = $published_scope = $tags = "";

        foreach ($dss_product_db_array as $product) {

            $product_id = $product['id'];
            //... more variables here...
            $tags = mysqli_real_escape_string($mysqli, $tags);              

            if (!mysqli_query($mysqli, $mainProdQueryStmt)) {
                printf("Errormessage: %s\n", mysqli_error($mysqli));
            }

            $mainProdQuery->bind_param("isssssssssss", $product_id, $product_title, $body_html, $vendor, $product_type, $created_at, 
                $handle, $updated_at, $published_at, $template_suffix, $published_scope, $tags);
            $mainProdQuery->execute();
    //      $mainProdQuery->close();
       }

更新

实施了此处提到的修复: 1.停止使用mysqli_real_escape_string 2. 在循环外绑定变量 3. 仅使用面向对象的方法,而不是像 mysqli_query($mysqli, $mainProdQueryStmt) VS $mysqli->prepare($mainProdQueryStmt) 那样混合它们,因为它应该是 - 这解决了“?”错误报告占位符语法错误

现在一切正常,没有错误。

更新代码:

    $mainProdQueryStmt = "INSERT INTO dss_products (`product_id`, `title`, `body_html`, `vendor`, `product_type`, `created_at`, `handle`, `updated_at`, `published_at`, `template_suffix`, `published_scope`, `tags`) 
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
        ON DUPLICATE KEY UPDATE 
            product_id = VALUES(product_id), 
            title = VALUES(title), 
            body_html = VALUES(body_html),
            vendor = VALUES(vendor), 
            product_type = VALUES(product_type), 
            created_at = VALUES(created_at), 
            handle = VALUES(handle), 
            updated_at = VALUES(updated_at), 
            published_at = VALUES(published_at), 
            template_suffix = VALUES(template_suffix), 
            published_scope = VALUES(published_scope), 
            tags = VALUES(tags)";

    $mainProdQuery = $mysqli->prepare($mainProdQueryStmt);
    if ($mainProdQuery === FALSE) {
        die($mysqli->error);
    }

    $product_id = $product_title = $body_html = $vendor = $product_type = $created_at = $handle = $updated_at = $published_at = $template_suffix = $published_scope = $tags = "";
    $mainProdQuery->bind_param("isssssssssss", $product_id, $product_title, $body_html, $vendor, $product_type, $created_at, 
        $handle, $updated_at, $published_at, $template_suffix, $published_scope, $tags);

    if ($mainProdQuery) {

        foreach ($dss_product_db_array as $product) {

            $product_id = $product['id'];
            $product_title = $product['title'];
            $body_html = $product['body_html'];
            $vendor = $product['vendor'];
            $product_type = $product['product_type'];
            $created_at = $product['created_at'];
            $handle = $product['handle'];
            $updated_at = $product['updated_at'];   
            $published_at = $product['published_at'];
            $template_suffix = $product['template_suffix'];
            $published_scope = $product['published_scope'];
            $tags = $product['tags'];

            if (!$mysqli->prepare($mainProdQueryStmt)) {
                printf("Errormessage: %s\n", $mysqli->error);
            }
            $mainProdQuery->execute();
        }
    }

【问题讨论】:

  • 您的代码没有意义。您稍后会使用准备好的语句,您正在使用mysqli_real_escape_string() 并且有一些未知变量。好的,你在下面有答案,处理这些。我现在就带路。
  • 为了使用占位符,您需要使用->prepare() 而不是mysqli_query()$mysqli->prepare($mainProdQueryStmt) 不是 mysqli_query($mysqli, $mainProdQueryStmt)
  • 如果它覆盖了同一行,那么你需要看看你的KEY
  • 注意:mysqli 的面向对象接口明显不那么冗长,使代码更易于阅读和审核,并且不容易与过时的mysql_query 接口混淆。在您对程序风格投入过多之前,值得转换一下。示例:$db = new mysqli(…)$db->prepare("…") 程序接口是 PHP 4 时代引入的 mysqli API 的产物,不应在新代码中使用。

标签: php mysql mysqli


【解决方案1】:

您在正确准备之前运行查询,然后在事后尝试绑定到不正确类型的东西,它不是语句句柄而是结果集。您需要以这种方式构建它:

$mainProdQueryStmt = "INSERT INTO products (`product_id`, `title`, `body_html`, `vendor`, `product_type`, `created_at`, `handle`, `updated_at`, `published_at`, `template_suffix`, `published_scope`, `tags`) 
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    ON DUPLICATE KEY UPDATE 
        product_id = VALUES(product_id), 
        ...
        tags = VALUES(tags)";

// Prepare the statement to get a statement handle
$stmt = $mysqli->prepare($mainProdQueryStmt);

foreach ($dss_product_db_array as $product) {
    // Bind to this statement handle the raw values (non-escaped)
    $stmt->bind_param("isssssssssss",
        $product['id'], $product['title'], ...);

    // Execute the query
    $stmt->execute();
}

尽量避免创建大量丢弃的变量,只需将直接绑定到相关值,例如$product 中的值。这些变量没有任何用处,只会给愚蠢的错误带来机会。

【讨论】:

  • 结果集是什么意思?
  • 没有必要继续准备同样的声明。
  • @barmar 我的意思是一个result set 对象,它是你从query() 调用中得到的。看起来$mainProdQuery 从未在原始文件中正确分配,但可能是该查询的结果。
  • 我认为这是准备的结果,但他从未完成将代码转换为准备好的语句。
  • 赞成关于无用变量的建议,谢谢!
【解决方案2】:

当你使用占位符时,你必须使用mysqli_prepare(),你不能使用mysqli_query()。看起来您打算这样做,但不知何故该代码丢失了,因为您使用了一个从未分配过的变量 $mainProdQuery

您应该只在循环外准备一次查询并绑定参数。然后在循环内调用execute()

$mainProdQueryStmt = "INSERT INTO products (`product_id`, `title`, `body_html`, `vendor`, `product_type`, `created_at`, `handle`, `updated_at`, `published_at`, `template_suffix`, `published_scope`, `tags`) 
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    ON DUPLICATE KEY UPDATE 
        product_id = VALUES(product_id), 
        title = VALUES(title), 
        body_html = VALUES(body_html),
        vendor = VALUES(vendor), 
        product_type = VALUES(product_type), 
        created_at = VALUES(created_at), 
        handle = VALUES(handle), 
        updated_at = VALUES(updated_at), 
        published_at = VALUES(published_at), 
        template_suffix = VALUES(template_suffix), 
        published_scope = VALUES(published_scope), 
        tags = VALUES(tags)";
$mainProdQuery = $mysqli->prepare($mainProdQueryStmt);
$mainProdQuery->bind_param("isssssssssss", $product_id, $product_title, $body_html, $vendor, $product_type, $created_at, 
            $handle, $updated_at, $published_at, $template_suffix, $published_scope, $tags);
foreach ($dss_product_db_array as $product) {

    $product_id = $product['id'];
    //... more variables here...
    $mainProdQuery->execute();
}

【讨论】:

    【解决方案3】:

    尝试使用 PDO(PhP Data Objects) 准备好的语句。使用和跨数据库工作不那么痛苦,即可以与任何 RDBMS 一起使用。请参阅 PDO Official Documentationhere

    【讨论】:

    • 这是一个评论和一个建议。它不能解决问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-18
    • 1970-01-01
    • 2019-11-04
    • 2016-01-12
    • 2011-07-26
    相关资源
    最近更新 更多