1

My Table:

  • customer_id INT (PRIMARY KEY)
  • purchased_products JSON
  • refunded_products = JSON

Expected values

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

The following SQL works as expected. Great!

 -- 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") 

However, my PDO satements in my application arent so good.

$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"']
  ]
]


My Connection

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

}

Error message

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '['3784835']) ON DUPLICATE KEY UPDATE purchased_products = JSON_ARRAY_INSERT(purc' at line 1

13
  • Your query has 3 parameters but you only pass 2, so you have to pass the value for purchased_products twice once if use in the INSERT and once for use in the UPDATE Commented Dec 17, 2021 at 15:46
  • But my query only has two params. customer_id and purchased_products. Commented Dec 17, 2021 at 15:57
  • Can you show us your connection parameter (not the password) but all the others Commented Dec 17, 2021 at 15:59
  • I want to see what you set ATTR_EMULATE_PREPARES to Commented Dec 17, 2021 at 16:10
  • @RiggsFolly I had suspected this was something to do with the JSON syntax in the initial INSERT vs the UPDATE Commented Dec 17, 2021 at 16:25

1 Answer 1

2

This should fix the problem:

$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'],
  ]
];

Explanation of changes:

Removed [ and ] in VALUES(:customer_id, [:purchased_products])

Now it looks like this:

VALUES(:customer_id, :purchased_products)

This change will avoid the error during the execute().

New param in JSON_ARRAY_INSERT: purchased_products_json

Now it looks like this:

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

To avoid the error now we need two params with small diferences. One for the INSERT (purchased_products) and other for the UPDATE (purchased_produtcs_json) because they have different formats despite same values.

In data array, changed 'purchased_products' => '"36"'

Now it looks like this:

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

because we will use it during INSERT stament, and we need to set it as new JSON array value with correct format and because we already removed the [ and ] in the previous INSERT statement.

In data array, added new param: 'purchased_products_json'

In order to UPDATE the field, the value format should be different, so we need this new param. It looks like this:

'purchased_products_json' => '36'

avoiding the use of [ and ]. You can see some information about JSON_ARRAY_INSERT in mariadb documentation

Sign up to request clarification or add additional context in comments.

3 Comments

that you so much for your efforts and I can see what your changes mean, it makes sense. Unfortunately I dont return to the office until Monday. However this will be the first thing I do and I will defo complete the question / answer etc.
No hurry. Thanks. Be sure to verify it first because I am not able to reproduce it (well, I can, but too much work :-))
yup that nailed it. You were right to add the extra param for the update. Great work, thanks again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.