dang
dang

Reputation: 2412

SQL query to parse JSON

I have the user table with user_id and user_details. it contains the JSON data in string format as shown below:

1-

[{"name":"question-1","value":"sachin","label":"Enter your name?"},
    {"name":"question-2","value":"[email protected]","label":"Enter your email?"},
    {"name":"question-3","value":"xyz","label":"Enter your city?"}]

2-

[{"name":"question-1","value":"sachin123","label":"Enter your name?"},
    {"name":"question-2","value":"[email protected]","label":"Enter your email?"},
    {"name":"question-3","value":"xyz","label":"Enter your city?"},
    {"name":"question-4","value":"red","label":"Enter your favourite color?"}]

3-

[{"name":"question-1","value":"","label":"Enter your name?"},
    {"name":"question-3","value":"xyz","label":"Enter your city?"},
    {"name":"question-4","value":"red","label":"Enter your favourite color?"}]

4-

[{"name":"question-1","value":"","label":"Enter your name?"},
    {"name":"question-2","value":"[email protected]","label":"Enter your email?"},
    {"name":"question-3","value":"abc","label":"Enter your city?"},
    {"name":"question-4","value":"pink","label":"Enter your favourite color?"}]

The expected output is:

row  Enter your name? | Enter your email?   | Enter your city?  | Enter your favourite color?
1    sachin           | [email protected]     | xyz               | -
2    sachin123        | [email protected]     | xyz               | red
3    -                | -                   | xyz               | blue
4    -                | [email protected]     | abc               | pink

I have tried doing it through PHP, it is possible by converting JSON to array and then comparing it. Is there a simpler way to get it directly using MySQL query?

Upvotes: 0

Views: 253

Answers (1)

Bill Karwin
Bill Karwin

Reputation: 562250

I came up with this solution:

SELECT user_id,
    COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(user_details, CONCAT(q1, '.value'))), ''), '-') AS 'Enter your name?',
    COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(user_details, CONCAT(q2, '.value'))), ''), '-') AS 'Enter your email?',
    COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(user_details, CONCAT(q3, '.value'))), ''), '-') AS 'Enter your city??',
    COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(user_details, CONCAT(q4, '.value'))), ''), '-') AS 'Enter your favorite color?'
FROM (
    SELECT user_id, user_details,
    SUBSTRING_INDEX(JSON_UNQUOTE(JSON_SEARCH(user_details, 'one', 'question-1')), '.', 1) AS q1,
        SUBSTRING_INDEX(JSON_UNQUOTE(JSON_SEARCH(user_details, 'one', 'question-2')), '.', 1) AS q2,
        SUBSTRING_INDEX(JSON_UNQUOTE(JSON_SEARCH(user_details, 'one', 'question-3')), '.', 1) AS q3,
        SUBSTRING_INDEX(JSON_UNQUOTE(JSON_SEARCH(user_details, 'one', 'question-4')), '.', 1) AS q4
    FROM users) t

Output:

+---------+------------------+-------------------+-------------------+----------------------------+
| user_id | Enter your name? | Enter your email? | Enter your city?? | Enter your favorite color? |
+---------+------------------+-------------------+-------------------+----------------------------+
|       1 | sachin           | [email protected]   | xyz               | -                          |
|       2 | sachin123        | [email protected]   | xyz               | red                        |
|       3 | -                | -                 | xyz               | red                        |
|       4 | -                | [email protected]   | abc               | pink                       |
+---------+------------------+-------------------+-------------------+----------------------------+

But this doesn't label the columns dynamically from the label found in each question. It's problematic to do that, because there's no guarantee that the label corresponding to question-1 is the same on every row, or present on any given row. So you're going to have to decide what the label should be and hard-code the column aliases in the query before you prepare() the query.

Ultimately, it's probably simpler to do this in PHP as you had already done.

Upvotes: 1

Related Questions