How to use a JSON stored procedure argument to insert multiple records?

Viewed 24

I have a linking table between two tables, ja1_surveyors and ja1_stores. I'm trying to writ a stored procedure that will take three arguments, the third being a json array of store_id.

I've tried this, but I know it's not correct:

/*
    ========================================================================================
    Set the list of stores for a surveyor in a survey. Used with template to create the list
    a user sees to edit, copy and delete surveyors in a survey
    Accepts three arguments:
        arg_srvy_id     Survey key
        arg_srvr_id     Surveyor key
        STORE_LIST  JSON value holding a list of store keys assigned to this survey/surveyor
        STORE_LIST JSON should be in the form: '{store_id:val1},{store_id:val2}' etc.
    ========================================================================================
*/
DROP PROCEDURE IF EXISTS SURVEYOR_LINK_STORES;

DELIMITER //

CREATE PROCEDURE SURVEYOR_LINK_STORES( IN arg_srvy_id INT(11),IN arg_srvr_id INT(11),IN STORE_LIST JSON)
BEGIN
    /*  Remove all links for this surveyor to stores for this survey    */
    DELETE FROM `ja1_storesurveyor`
    WHERE `lnk_strsrvr_srvy_id` = arg_srvy_id AND `lnk_strsrvr_srvr_id` = arg_srvr_id;
    /*  Add links between this survey and surveyor for each key in STORE_LIST   */
    INSERT INTO `ja1_store_surveyor`
    (
        `lnk_strsrvr_srvy_id`,
        `lnk_strsrvr_srvr_id`,
        `lnk_strsrvr_store_id`
    )
    SELECT 
        arg_srvy_id,
        arg_srvr_id,
        STORE_LIST->>`$.store_id`
    FROM STORE_LIST;
END

DELIMITER ;

The problem seems to be the select part of the insert statement.

All of the columns are INT(11). And I'm using MySQL version 5.6.41-84.1

What am I missing?

1 Answers

The best way to do this is with JSON_TABLE() but it requires MySQL 8.0.

Edit: When I wrote this answer, your original question did not make it clear you were using an old version of MySQL Server.

CREATE PROCEDURE SURVEYOR_LINK_STORES(
  IN arg_arg_srvy_id INT,
  IN arg_arg_srvr_id INT,
  IN arg_STORE_LIST JSON)
BEGIN
    /*  Remove all links for this surveyor to stores for this survey */
    DELETE FROM `ja1_storesurveyor`
    WHERE `lnk_strsrvr_srvy_id` = arg_srvy_id 
      AND `lnk_strsrvr_srvr_id` = arg_srvr_id;

    /*  Add links between this survey and surveyor for each key in STORE_LIST */
    INSERT INTO `ja1_store_surveyor`
    (
        `lnk_strsrvr_srvy_id`,
        `lnk_strsrvr_srvr_id`,
        `lnk_strsrvr_store_id`
    )
    SELECT 
        arg_srvy_id,
        arg_srvr_id,
        j.store_id
    FROM JSON_TABLE(
      arg_STORE_LIST, '$[*]' COLUMNS(
        store_id VARCHAR(...) PATH '$'
      )
    ) AS j;
END

I'm guessing the appropriate data type for store_id is a varchar, but I don't know how long the max length should be.


Re your comment: MySQL 5.6 doesn't have any JSON data type, so your stored procedure won't work as you wrote it (the arg_STORE_LIST argument cannot use the JSON data type).

FYI, MySQL 5.6 past its end-of-life in February 2021, so the version you are using won't get any more bug fixes or security fixes. You should really upgrade, regardless of the JSON issue.

The equivalent code to insert multiple rows in MySQL 5.6 is a lot of work and code to write. I'm not going to write an example for such an old version of MySQL.

You can find other examples on Stack Overflow with the general principle. It involves taking the argument as a VARCHAR, not JSON, and writing a WHILE loop to picking apart substrings of the varchar.

Related