在预准备语句中使用问号占位符时出现MySQL语法错误

时间:2017-12-22 01:48:01

标签: php mysql mysqli

尝试了我能想到的一切,我已经缩小到“?”占位符。

我试过更换“?”带有随机文本的占位符,一切运行良好(当然除了它会覆盖同一行)。

我得到的错误:

  

您的SQL语法有错误;检查与MySQL服务器版本对应的手册,以便在“?,?,?,?,?,?,?,?,?,?,?,?”附近使用正确的语法               在DUPLICATE KEY UPDATE                   产品'在第2行

这是我的代码(我会提供更多,但除了这个bug之外它都运行良好,如果我删除“?”占位符,那么除了值不是动态的,所有的工作都很完美,但请问你是否怀疑问题在别处):

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

3 个答案:

答案 0 :(得分:3)

使用占位符时必须使用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();
}

答案 1 :(得分: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中那样。变量没有任何用处,只会为愚蠢的错误带来机会。

答案 2 :(得分:-1)

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