Home  >  Q&A  >  body text

Rewrite the title as: Convert JSON array to rows in MySQL

<p><strong>Update: </strong> This is now possible in MySQL 8 via the JSON_TABLE function: https://dev.mysql.com/doc/refman/8.0/en/json-table-functions. html< /p> </p><p>I like the new JSON functions in MySQL 5.7, but I'm having trouble trying to merge values ​​from JSON into a normal table structure. </p> <p>Getting JSON, manipulating it, extracting arrays from it, and more is easy. JSON_EXTRACT all the way. But what about the other way around, from JSON array to row? Maybe I'm interested in the existing MySQL JSON functionality, but I haven't been able to figure that out. </p> <p>For example, suppose I have a JSON array and want to insert a row for each element in the array and its value? The only way I've found is to write a bunch of JSON_EXTRACT(... '$[0]') JSON_EXTRACT(... '$[1]') etc and join them together. </p> <p>Alternatively, suppose I have a JSON array and want to GROUP_CONCAT() it into a single comma-separated string? </p> <p>In other words, I know I can do this:</p> <pre class="brush:php;toolbar:false;">SET @j = '[1, 2, 3]'; SELECT GROUP_CONCAT(JSON_EXTRACT(@j, CONCAT('$[', x.n, ']'))) AS val FROM ( SELECT 0 AS n UNION SELECT 1 AS n UNION SELECT 2 AS n UNION SELECT 3 AS n UNION SELECT 4 AS n UNION SELECT 5 AS n ) x WHERE x.n < JSON_LENGTH(@j);</pre> <p>But it hurts my eyes. And my heart. </p> <p>How can I do something like this:</p> <pre class="brush:php;toolbar:false;">SET @j = '[1, 2, 3]'; SELECT GROUP_CONCAT(JSON_EXTRACT(@j, '$[ * ]'))</pre> <p>...and concatenate the values ​​in the array with the JSON array itself? </p> <p>I think what I'm looking for here is some kind of JSON_SPLIT , something like: </p> <pre class="brush:php;toolbar:false;">SET @j = '[1, 2, 3]'; SELECT GROUP_CONCAT(val) FROM JSON_SPLIT(JSON_EXTRACT(@j, '$[ * ]'), '$')</pre> <p>If MySQL had a proper STRING_SPLIT(val, 'separator') table-returning function, I could hack it (the damn escape), but that doesn't work either. </p>
P粉265724930P粉265724930419 days ago645

reply all(2)I'll reply

  • P粉827121558

    P粉8271215582023-08-28 13:36:44

    It's true that denormalizing to JSON is not a good idea, but sometimes you need to deal with JSON data, and there is a way to extract a JSON array into rows in a query.

    The trick is to perform a join on a temporary or inline index table, which gives you a row for each non-null value in the JSON array. That is, if you have a table with values ​​0, 1, and 2, and you join it to a JSON array "fish" that contains two entries, then Fish[0] matches 0, resulting in a row, and Fish1 matches 1, resulting in the second row, but fish[2] is null, so it does not match 2 and no row is produced in the join. You need as many numbers in the index table as the maximum length of any array in the JSON data. This is a bit of a hack, and as painful as the OP's example, but it's very convenient.

    Example (requires MySQL 5.7.8 or higher):

    CREATE TABLE t1 (rec_num INT, jdoc JSON);
    INSERT INTO t1 VALUES 
      (1, '{"fish": ["red", "blue"]}'), 
      (2, '{"fish": ["one", "two", "three"]}');
    
    SELECT
      rec_num,
      idx,
      JSON_EXTRACT(jdoc, CONCAT('$.fish[', idx, ']')) AS fishes
    FROM t1
      -- Inline table of sequential values to index into JSON array
    JOIN ( 
      SELECT  0 AS idx UNION
      SELECT  1 AS idx UNION
      SELECT  2 AS idx UNION
      -- ... continue as needed to max length of JSON array
      SELECT  3
      ) AS indexes
    WHERE JSON_EXTRACT(jdoc, CONCAT('$.fish[', idx, ']')) IS NOT NULL
    ORDER BY rec_num, idx;

    turn out:

    +---------+-----+---------+
    | rec_num | idx | fishes  |
    +---------+-----+---------+
    |       1 |   0 | "red"   |
    |       1 |   1 | "blue"  |
    |       2 |   0 | "one"   |
    |       2 |   1 | "two"   |
    |       2 |   2 | "three" |
    +---------+-----+---------+

    Looks like the MySQL team may be adding a JSON_TABLE function in MySQL 8 to make this easier. (http://mysqlserverteam.com/mysql-8-0-labs -json-aggregation-functions/) (MySQL Teamhas addedJSON_TABLE function.)

    reply
    0
  • P粉403804844

    P粉4038048442023-08-28 09:32:06

    Here's how to use JSON_TABLE in MySQL 8:

    SELECT *
         FROM
           JSON_TABLE(
             '[5, 6, 7]',
             "$[*]"
             COLUMNS(
               Value INT PATH "$"
             )
           ) data;

    You can also use it as a general-purpose string splitting function that MySQL lacks (similar to PG's regexp_split_to_table or MSSQL's STRING_SPLIT) by taking the delimited string and converting it to a JSON string:

    set @delimited = 'a,b,c';
    
    SELECT *
         FROM
           JSON_TABLE(
             CONCAT('["', REPLACE(@delimited, ',', '", "'), '"]'),
             "$[*]"
             COLUMNS(
               Value varchar(50) PATH "$"
             )
           ) data;

    reply
    0
  • Cancelreply