0

I'm trying to learn SQL but hitting a wall with the following problem. I can solve it easily using imperative programming but would like to know if it's possible to solve this problem using just a query:

Input

Table 1 (users)

ID  | Firstname
--------------
1   | Felix
2   | Michael
3   | Tobias

Table 2 (hobbies)

ID  | Hobby     | User
------------------------
1   | cooking   | 1
2   | cat       | 1
3   | piano     | 2

Wanted Output

{
    "users": [{
            "firstname": "Felix",
            "hobbies": [{
                "id": 1,
                "name": "cooking"
            }, {
                "id": 2,
                "name": "cat"
            }]
        },
        {
            "firstname": "Michael",
            "hobbies": [{
                "id": 3,
                "name": "piano"
            }]
        },
        {
            "firstname": "Tobias",
            "hobbies": []
        }
    ]
}

Doesn't need to be directly JSON of course. With joins I've come so far that either a row is created for each hobby x user (two rows for Felix)

Felix | cooking
Felix | cat
Michael | piano

or that some information got lost (Felix' cat got lost)

Felix | cooking
Michael | piano
3
  • Take a look at the MS Docs here learn.microsoft.com/en-us/sql/relational-databases/json/… if you have SQL Server 2016 Commented May 9, 2017 at 11:38
  • Just a basic MySQL server running on Ubuntu Commented May 9, 2017 at 11:39
  • 1
    Quite easy with Postgres: rextester.com/SQA15827 don't know about MySQL Commented May 9, 2017 at 11:49

1 Answer 1

2

Second Update

I don't like this it feels too much like "brute force", and I guess there is a more elegant way ...

select concat('{ "users": [', group_concat(json.hobbies), '] }') as hobbies
from
(
    select concat('{"firstname": "',u.firstname,'", "hobbies": [', group_concat(json_object('id',h.id,'name',h.hobby),''), ']}') hobbies
    from users u
        left join hobbies h on u.id = h.user
    group by u.id
    order by u.firstname
) as json

Output

{ "users": [{"firstname": "Felix", "hobbies": [{"id": 1, "name": "cooking"},{"id": 2, "name": "cat"}]},{"firstname": "Michael", "hobbies": [{"id": 3, "name": "piano"}]},{"firstname": "Tobias", "hobbies": [{"id": null, "name": null}]}] }

First Update

I've lost my battle with MySQL JSON (for now). The closest I could get was the following, which I guess might still be of some use:

select u.firstname, group_concat(json_object('id',h.id,'name',h.hobby),'') hobbies
from users u
left join hobbies h on u.id = h.user
group by u.id
order by u.firstname

Output

+-----------+-------------------------------------------------------+
| firstname | hobbies                                               | 
+-----------+-------------------------------------------------------+
| Felix     | {"id": 1, "name": "cooking"},{"id": 2, "name": "cat"} |
| Michael   | {"id": 3, "name": "piano"}                            |
| Tobias    | {"id": null, "name": null}                            | 
+-----------+-------------------------------------------------------+    

Original Answer

Not sure about JSON, will this suffice for the SQL side?

select
    u.id,
    u.firstname,
    group_concat(h.hobby ORDER BY h.ID SEPARATOR ',') as hobbies
from
    my_users u
    LEFT JOIN hobbies h ON
    u.ID = h.user
group by
    u.id,
    u.firstname

Output

+----+-----------+-------------+
| id | firstname |   hobbies   |
+----+-----------+-------------+    
|  1 | Felix     | cooking,cat |
|  2 | Michael   | piano       |
|  3 | Tobias    | NULL        |
+----+-----------+-------------+ 
Sign up to request clarification or add additional context in comments.

5 Comments

I like the idea, but I need the ID sadly
It could be added in with the hobbies without difficulty, to look (e.g.) like this: 1: cooking, 2: cat. If that's good enough, I'll make the edit. But in the meantime, I'll see if I can find a full JSON output. I like learning this stuff, so ...
Not too sure under what circumstances you get notified, but in case you didn't already see, I've made an attempt at getting full JSON output from MySQL. It seems to work well, though I'd be surprised be surprised if there aren't more elegant ways to do it. Will be interested in your feedback.
Indeed I did not get notified about the edit of your answer. For my task this solution works perfectly fine. The question I have now is if it's better to build such unsual queries as you call them "brute force" or to manipulate the data in the retrieving code
Oh, I'd definitely use it if it works. But it will be worth keeping an eye out for other later answers to your question in case anyone has improvements. Alternatively​, you could ask a new question specifically asking for improvements to this code. I attempted a solution closer to the one that @a_horse_with_no_name supplied, but it kept escaping parts of the inner JSON objects, and I could make neither head nor tail of the MySQL documentation on its other JSON functions. But others will have more experience and know whether there is a better way. In the meantime keep your other code lean.

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.