使用 JSON 数组作为值时的 MySQL 语法错误

Posted

技术标签:

【中文标题】使用 JSON 数组作为值时的 MySQL 语法错误【英文标题】:MySQL Syntax Error when using JSON array as value 【发布时间】:2022-01-20 12:28:58 【问题描述】:

我的桌子:

customer_id INT(主键) purchased_products JSON refunded_products = JSON

预期值

12345 ["32","33","34"] ["31","38","39"]

以下 SQL 按预期工作。太好了!

 -- Insert a new row into the purchased products table
INSERT INTO dc_purchased_products (
    user_id, -- INT
    purchased_products -- JSON
)

-- 1) The user ID (primary key)
-- 2) Formatted json array with the first purchased product ID
VALUES ( 12345, '["36"]' )

-- If the user id already exists, append the existing array with the product ID
ON DUPLICATE KEY UPDATE 

-- JSON_ARRAY_INSERT(existing purchases array, index, product_id)
purchased_products = JSON_ARRAY_INSERT(purchased_products, '$[0]', "36") 

但是,我的应用程序中的 PDO 语句并不是那么好。

$item = [
  'statement' => "INSERT INTO purchased_products 
                        (customer_id, purchased_products) 
                  VALUES(:customer_id, [:purchased_products]) 
                    ON DUPLICATE KEY 
                    UPDATE purchased_products = JSON_ARRAY_INSERT(purchased_products, '$[0]',:purchased_products)",
  'data' => [
    ['customer_id' => 12345, 'purchased_products' => '"36"'],
    ['customer_id' => 12345, 'purchased_products' => '"37"']
  ]
]


我的连接

$this->connection = new PDO("mysql:host=$servername;dbname=$database", $u, $p, [
  PDO::MYSQL_ATTR_SSL_KEY                => $ck,
  PDO::MYSQL_ATTR_SSL_CERT               => $cc,
  PDO::MYSQL_ATTR_SSL_CA                 => $sc,
  PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
]);

$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


$statement = $this->connection->prepare($item['statement']);
foreach ($item['data'] as $rowData) 

    foreach ($rowData as $key => $param) 
        $statement->bindValue(':' . $key, $param);
    

    try 
        $success = $statement->execute();
    

    catch (PDOException $e) 
        pre($e->getMessage());        
    


错误信息

SQLSTATE[42000]: 语法错误或访问冲突:1064 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在 '['3784835']) ON DUPLICATE KEY UPDATE purchase_products = JSON_ARRAY_INSERT(purc' at line 1 附近使用正确的语法

【问题讨论】:

您的查询有 3 个参数,但您只传递了 2 个参数,因此如果在 INSERT 中使用,您必须将 purchased_products 的值传递两次,在 UPDATE 中使用一次 但我的查询只有两个参数。 customer_id 和购买的产品。 你能告诉我们你的连接参数(不是密码),但所有其他的 我想看看你把ATTR_EMULATE_PREPARES设置成什么 更新问题 【参考方案1】:

这应该可以解决问题:

$item = [
  'statement' => "INSERT INTO purchased_products 
                        (customer_id, purchased_products) 
                  VALUES(:customer_id, :purchased_products) 
                    ON DUPLICATE KEY 
                    UPDATE purchased_products = JSON_ARRAY_INSERT(purchased_products, '$[0]',:purchased_products_json)",
  'data' => [
    ['customer_id' => 12345, 'purchased_products' => '["36"]', 'purchased_products_json' => '36'],
    ['customer_id' => 12345, 'purchased_products' => '["37"]', 'purchased_products_json' => '37'],
  ]
];

变更说明:

删除了VALUES(:customer_id, [:purchased_products])中的[]

现在看起来像这样:

VALUES(:customer_id, :purchased_products)

此更改将避免execute() 期间的错误。

JSON_ARRAY_INSERT 中的新参数:purchased_products_json

现在看起来像这样:

JSON_ARRAY_INSERT(purchased_products, '$[0]',:purchased_products_json)

为了避免错误,现在我们需要两个差异很小的参数。一个用于 INSERT (purchased_products),另一个用于 UPDATE (purchased_produtcs_json),因为尽管值相同,但它们具有不同的格式。

data数组中,更改了'purchased_products' => '"36"'

现在看起来像这样:

'purchased_products' => '["36"]'

因为我们将在 INSERT 语句中使用它,并且我们需要将其设置为格式正确的新 JSON 数组值,并且因为我们已经在前面的 INSERT 语句中删除了 []

data数组中,新增参数:'purchased_products_json'

为了更新字段,值格式应该不同,所以我们需要这个新参数。它看起来像这样:

'purchased_products_json' => '36'

避免使用[]。你可以在mariadb documentation看到一些关于JSON_ARRAY_INSERT的信息

【讨论】:

您非常感谢您的努力,我可以看到您的更改意味着什么,这是有道理的。不幸的是,我直到星期一才回到办公室。然而,这将是我做的第一件事,我将完成问题/答案等。 不着急。谢谢。请务必先验证它,因为我无法重现它(嗯,我可以,但工作量太大:-)) 是的,成功了。您为更新添加额外的参数是正确的。干得好,再次感谢。

以上是关于使用 JSON 数组作为值时的 MySQL 语法错误的主要内容,如果未能解决你的问题,请参考以下文章

JsonResult作为Action返回值时的错误

Mysql下SELECT的结果集作为UPDATE的WHERE条件时的SQL语法

mysql JSON路径遍历数组的正确语法?

在两者中使用基类和派生类作为数组时的循环

从 MySQL JSON 列中提取 JSON 对象的值作为数组

使用 CURDATE() 作为默认值时在 mysql 中创建表失败