62

How create json format with group-concat mysql?

(I use MySQL)

Example1:

table1:

email            |    name  |   phone
-------------------------------------
my1@gmail.com    | Ben      | 6555333
my2@gmail.com    | Tom      | 2322452
my2@gmail.com    | Dan      | 8768768
my1@gmail.com    | Joi      | 3434356

like syntax code that not give me the format:

select email, group-concat(name,phone) as list from table1 
group by email

output that I need:

email         |    list
------------------------------------------------
my1@gmail.com |  {name:"Ben",phone:"6555333"},{name:"Joi",phone:"3434356"}
my2@gmail.com |  {name:"Tom",phone:"2322452"},{name:"Dan",phone:"8768768"}

Thanks

Gruber
  • 1,750
  • 4
  • 22
  • 42
Ben
  • 23,101
  • 33
  • 104
  • 161

8 Answers8

83

With the newer versions of MySQL, you can use JSON_OBJECT function to achieve the desired result, like so:

GROUP_CONCAT(
  JSON_OBJECT(
    'name', name,
    'phone', phone
  )
) AS list

To get the SQL response ready to be parsed as an array:

CONCAT(
  '[',
  GROUP_CONCAT(
    JSON_OBJECT(
      'name', name,
      'phone', phone
    )
  ),
  ']'
) AS list

This will give you a string like: [{name: 'ABC', phone: '111'}, {name: 'DEF', phone: '222'}] which can be JSON parsed. Hope this helps.

myusuf
  • 10,151
  • 8
  • 32
  • 46
81

Try this query -

SELECT
  email,
  GROUP_CONCAT(CONCAT('{name:"', name, '", phone:"',phone,'"}')) list
FROM
  table1
GROUP BY
  email;

JSON format result -

+---------------+-------------------------------------------------------------+
| email         | list                                                        |
+---------------+-------------------------------------------------------------+
| my1@gmail.com | {name:"Ben", phone:"6555333"},{name:"Joi", phone:"3434356"} |
| my2@gmail.com | {name:"Tom", phone:"2322452"},{name:"Dan", phone:"8768768"} |
+---------------+-------------------------------------------------------------+
Devart
  • 110,991
  • 22
  • 156
  • 173
  • 6
    what would happen if name contains a double quote? – K2xL Dec 20 '13 at 20:17
  • It depends on ANSI_QUOTES SQL mode, if it is activated - then you should double " in names, othervise - it will work. – Devart Dec 23 '13 at 07:26
  • hmm this seems to surround the entire "list" json value with double quotes - meaning if you json_encode the entire result the field list will not be encoded and remains a string... – K2xL Jan 08 '14 at 21:19
  • 3
    sorry to say this is not a valid JSON... a JSON array is enclosed between [ and ] – Antonio Ortells Aug 17 '16 at 17:17
  • 1
    As a sidenote to my edit, you could use the new JSON functions in MySQL 5.7 if that is an option for you. See : https://dev.mysql.com/doc/refman/5.7/en/json-creation-functions.html#function_json-object – Mathieu de Lorimier Oct 21 '16 at 13:59
  • 4
    @AntonioOrtells, to make it valid you would, and I did, just adjust the part with `CONCAT('[', GROUP_CONCAT(…), ']') list`, this wraps it in array brackets and the comma from GROUP_CONCAT does the rest. – Adrian Föder May 18 '18 at 06:55
23

I hope this finds the right eyes.

You can use:

For arrays (documentation):

JSON_ARRAYAGG(col_or_expr) as ...

For objects (documentation):

JSON_OBJECTAGG(key, value) as ...
aero
  • 1,296
  • 1
  • 13
  • 26
Maciek Semik
  • 1,642
  • 18
  • 35
19

Devart's answer above is great, but K2xL's question is valid. The answer I found was to hexadecimal-encode the name column using HEX(), which ensures that it will create valid JSON. Then in the application, convert the hexadecimal back into the string.

(Sorry for the self-promotion, but) I wrote a little blog post about this with a little more detail: http://www.alexkorn.com/blog/2015/05/hand-rolling-valid-json-in-mysql-using-group_concat/

[Edit for Oriol] Here's an example:

SELECT email,
    CONCAT(
        '[',
        COALESCE(
            GROUP_CONCAT(
                CONCAT(
                    '{',
                    '\"name\": \"', HEX(name), '\", ',
                    '\"phone\": \"', HEX(phone), '\"',
                    '}')
                ORDER BY name ASC
                SEPARATOR ','),
            ''),
        ']') AS bData
FROM table
GROUP BY email

Also note I've added a COALESCE in case there are no items for that email.

alexkorn
  • 315
  • 2
  • 6
  • Add the complex concat example in your answer. I think it's very helpful ;-) – Oriol Feb 09 '17 at 23:18
  • This solved my issue, other solutions failed when decoding the resulting json with invalid chars like tabs, slashes, ... – Mirko Oct 04 '17 at 09:53
  • 1
    the `name` and `phone` keys have to be in `""`(double quotes) to represent a valid json – kekko12 Apr 04 '18 at 17:00
  • kekko12: Fixed. Thanks! – alexkorn Apr 05 '18 at 18:16
  • `TO_BASE64` might lower the overcost that `HEX` introduce (ie: strings are shorter). But use https://stackoverflow.com/a/40235188/2342518 for nowadays MySQLs – Xenos May 17 '18 at 10:05
17

For Mysql 5.7.22+

    SELECT
        email,
        JSON_ARRAYAGG(
            JSON_OBJECT(
                'name', name,
                'phone', phone
            )
        ) AS list
    FROM table1
    GROUP BY email;

Result:

+---------------+-------------------------------------------------------------------+
| email         | list                                                              |
+---------------+-------------------------------------------------------------------+
| my1@gmail.com | [{"name":"Ben", "phone":6555333},{"name":"Joi", "phone":3434356}] |
| my2@gmail.com | [{"name":"Tom", "phone":2322452},{"name":"Dan", "phone":8768768}] |
+---------------+-------------------------------------------------------------------+

The only difference is that column list is now Json-valid, so you can parse directly as Json

Madacol
  • 1,651
  • 19
  • 19
3

Going off of @Devart's answer... if the field contains linebreaks or double quotation marks, the result will not be valid JSON.

So, if we know the "phone" field occasionally contains double-quotes and linebreaks, our SQL would look like:

SELECT
  email,
  CONCAT(
    '[',
    GROUP_CONCAT(CONCAT(
        '{name:"', 
        name, 
        '", phone:"', 
        REPLACE(REPLACE(phone, '"', '\\\\"'),'\n','\\\\n'), 
        '"}'
      )),
    ']'
  ) AS list
FROM table1 GROUP BY email;

If Ben phone has a quote in the middle of it, and Joi's has a newline, the SQL would give (valid JSON) results like:

[{name:"Ben", phone:"655\"5333"},{name:"Joi", phone:"343\n4356"}]
Jonathan Harford
  • 331
  • 1
  • 3
  • 9
3

Similar to Madacol's answer above, but slightly different. Instead of JSONARRAYAGG, you could also CAST AS JSON:

SELECT
        email,
       CAST( CONCAT(
        '[', 
           GROUP_CONCAT(
           JSON_OBJECT(
              'name', name,
              'phone', phone
            )
        ),']') AS JSON )
    FROM table1
    GROUP BY email;

Result:

+---------------+-------------------------------------------------------------------+
| email         | list                                                              |
+---------------+-------------------------------------------------------------------+
| my1@gmail.com | [{"name":"Ben", "phone":6555333},{"name":"Joi", "phone":3434356}] |
| my2@gmail.com | [{"name":"Tom", "phone":2322452},{"name":"Dan", "phone":8768768}] |
+---------------+-------------------------------------------------------------------+

Rahul Singh
  • 607
  • 1
  • 1
  • 9
  • what is your DBMS you can use json path in sql server – Amirhossein Jun 10 '20 at 19:34
  • sorry i missed that..This is for Mysql 5.7.26 – Rahul Singh Jun 11 '20 at 14:39
  • the only thing to keep in mind like when you use `GROUP_CONCAT` you can have only 1024 characters only. If your JSON has more length then I would suggest the below answer to follow. https://stackoverflow.com/a/58509829/8197832 – Subham Oct 21 '20 at 07:30
0

Use like this

SELECT email,concat('{name:"',ur_name_column,'",phone:"',ur_phone_column,'"}') as list FROM table1 GROUP BY email;

Cheers

Sundar G
  • 957
  • 1
  • 9
  • 25
  • Will throw a warning (and inconsistant results) since you're retrieving a non-grouped non-unique column with a `GROUP BY` clause (and will be prone to JSOn-injection if `ur_name_column` contains double quotes or blackslash) – Xenos May 17 '18 at 10:07