0

I have a MaraiDB (10.2.14) database containing a table where in one column JSON data is stored.

I'm puzzled as how to extract data from this column.

Example Data

SELECT 1 AS ID
     , '[{"name":"x","score":2},{"name":"y", "score":8},{"name":"z","score":3}]' AS REPLY
UNION ALL
SELECT 2 AS ID
     , '[{"name":"x","score":5},{"name":"y", "score":4},{"name":"z","score":3}]' AS REPLY
UNION ALL
SELECT 3 AS ID
     , '[{"name":"x","score":2},{"name":"y", "score":2},{"name":"z","score":6}]' AS REPLY
UNION ALL
SELECT 4 AS ID
     , '[{"name":"x","score":5},{"name":"y", "score":8},{"name":"z","score":6}]' AS REPLY

So how would I find all entries having "name":"x" and a "score":5. Additionally I need to get the "score" value of the "name":"y" of that entry.

My current dirty approach is

WITH JT1 AS (
        SELECT 1 AS ID
             , '[{"name":"x","score":2},{"name":"y", "score":8},{"name":"z","score":3}]' AS REPLY
        UNION ALL
        SELECT 2 AS ID
             , '[{"name":"x","score":5},{"name":"y", "score":4},{"name":"z","score":3}]' AS REPLY
        UNION ALL
        SELECT 3 AS ID
             , '[{"name":"x","score":2},{"name":"y", "score":2},{"name":"z","score":6}]' AS REPLY
        UNION ALL
        SELECT 4 AS ID
             , '[{"name":"x","score":5},{"name":"y", "score":8},{"name":"z","score":6}]' AS REPLY
)
SELECT ID
     , REGEXP_REPLACE(
         REGEXP_REPLACE( EXTRACTED, '^.*"y",\\s', '')
       , '[,\\]].*$', '') AS Y
     , EXTRACTED
FROM (
        SELECT ID
             , JSON_EXTRACT(REPLY, '$[*].name','$[*].score') EXTRACTED
        FROM JT1
) JT2
WHERE EXTRACTED RLIKE '"x", 5\\b'
;

So I first extract "name" and "score" which gives me column data like ["x", 5, "y", 4, "z", 3]. With that I do some nasty REGEXP search & replaces.

I feel there must be a better way.

I tried using COLUMN_CREATE, but "COLUMN_CREATE" seems not to be able to accept the result from JSON_EXTRACT as input. Now that I think about it, this seems logical as "name" and "score" here are properly ordered, but can I be sure it's always that sequence?

Can anyone give me a hint how to do this better?

1 Answer 1

2

If I understand what you need, a query like the following may be useful:

WITH `JT1` AS (
  SELECT 1 AS `ID`
  , '[{"name":"x","score":2},{"name":"y", "score":8},{"name":"z","score":3}]' AS `REPLY`
  UNION ALL
  SELECT 2 AS `ID`
  , '[{"name":"x","score":5},{"name":"y", "score":4},{"name":"z","score":3}]' AS `REPLY`
  UNION ALL
  SELECT 3 AS `ID`
  , '[{"name":"x","score":2},{"name":"y", "score":2},{"name":"z","score":6}]' AS `REPLY`
  UNION ALL
  SELECT 4 AS `ID`
  , '[{"name":"x","score":5},{"name":"y", "score":8},{"name":"z","score":6}]' AS `REPLY`
)
SELECT
  `ID`,
  `REPLY`,
  JSON_VALUE(
    `REPLY`,
    JSON_UNQUOTE(
      REPLACE(
        JSON_SEARCH(`REPLY`, 'one', 'y', NULL, '$[*].name'),
        'name',
        'score'
      )
    )
  ) `"name":"y"`
FROM
  `JT1`
WHERE
  JSON_VALUE(
    `REPLY`,
    JSON_UNQUOTE(
      REPLACE(
        JSON_SEARCH(`REPLY`, 'one', 'x', NULL, '$[*].name'),
        'name',
        'score'
      )
    )
  ) = 5;

See dbfiddle.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for that. I see that it works, but I do not understand it (yet). Unfortunately I'm not yet eligible for upvoting. I hope someone will do it for me.
@Skeeve Done. You can mark it as an answer though, right?

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.