Home > Software design >  mysql >5.7 JOIN two json tables returning only last unique entry
mysql >5.7 JOIN two json tables returning only last unique entry

Time:02-16

I am looking to use a join to replace a reference with a value in the following mysql

the output from the final function should be

{"Fav_Friend": "Ross", "castMember": "Elaine"}
{"Fav_Friend": "Gina", "castMember": "George"}
{"Fav_Friend": "Gina", "castMember": "Jerry"}
{"Fav_Friend": "Monica", "castMember": "Kramer"}
{"Fav_Friend": "Rachel", "castMember": "Numan"}

Note in this function we are changing

the key names -> works ok,    
      name->castmember
      favfriend->Fav_Friend

get last unique row that matches $.name -> works OK 
eg: {"Fav_Friend": "c1fcb509e6b34e5ba5d0a44329a88a94", "castMember": "Elaine"}

WITH lastEntry AS (
  SELECT m.*, ROW_NUMBER() OVER (PARTITION BY details->>'$.name' ORDER BY uid DESC) AS lE
  FROM people AS m
  ) SELECT 
      JSON_OBJECT('castMember',details->>'$.name','Fav_Friend',details->>'$.favfriend')
      FROM lastEntry WHERE lE = 1;

looking at other answers on SO I have tried adding a LEFT JOIN CAST but this returns an error

 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LEFT JOIN friends g on JSON_CONTAINS(m.details->>'$.favfriend', CAST(g.crew-' at line 6
 
WITH lastEntry AS (
  SELECT m.*, ROW_NUMBER() OVER (PARTITION BY details->>'$.name' ORDER BY uid DESC) AS lE
  FROM people AS m
  ) SELECT 
      JSON_OBJECT('castMember',details->>'$.name','Fav_Friend',details->>'$.favfriend')
      FROM lastEntry WHERE lE = 1
  LEFT JOIN friends g on JSON_CONTAINS(m.details->>'$.favfriend', CAST(g.crew->>'$.screen' as JSON), '$');

and also tried direct reference

LEFT JOIN friends g on JSON_CONTAINS(lastEntry.details->>'$.favfriend', CAST(g.crew->>'$.screen' as JSON), '$');

in case this is the wrong direction I also tried variations of

LEFT JOIN friends g on people.details->>'$.favfriend' = g.crew->>'$.screen';

how can I replace the guid with the screen name?

Here is the table data

    CREATE DATABASE castfriends
    DEFAULT CHARACTER SET = 'utf8mb4';

use castfriends;
CREATE TABLE `people` (
  `uid` int NOT NULL AUTO_INCREMENT COMMENT 'id',
  `details` json DEFAULT NULL COMMENT 'supporting fields for parent',
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb3;

insert into castfriends.people (details)  values 
(
  '{
    "guid" : "c14ad6a7e63a4f6c8d68b4bc3a3dd404",
    "name": "George",
    "favfriend":"062a55f932ea408e8f8f1914f1499a24"
  }'
),
(
  '{
    "guid" : "f4aec5a0043f4933a084cea137ebcff9",
    "name": "Elaine",
    "favfriend":"d8930c49405242d5923362b8818b93ad"
  }'
),
(
  '{
    "guid" : "c788335702eb413496c7d60e7041c34c",
    "name": "Jerry",
    "favfriend":"a846ec1c09844012bb1d3e64ae311bf8"
  }'
),
(
  '{
    "guid" : "30425947838149fda9f836a089605459",
    "name": "Kramer",
    "favfriend":"a846ec1c09844012bb1d3e64ae311bf8"
  }'
),
(
  '{
    "guid" : "18dc6c62c2554ef796c684164d72eee0",
    "name": "Numan",
    "favfriend":"a846ec1c09844012bb1d3e64ae311bf8"
  }'
),
(
  '{
    "guid" : "c15ea8d20f8d4906a1d9704e347e5d81",
    "name": "Elaine",
    "favfriend":"c1fcb509e6b34e5ba5d0a44329a88a94"
  }'
),
(
  '{
    "guid" : "975f1fdc11a64d4ba716513f5d08c23d",
    "name": "Jerry",
    "favfriend":"062a55f932ea408e8f8f1914f1499a24"
  }'
),
(
  '{
    "guid" : "f1fb99a8ac1342c5b266af44dfa92db1",
    "name": "Kramer",
    "favfriend":"49578c5a85a1454597b911e8c6300828"
  }'
),
(
  '{
    "guid" : "feeab20a78bd4297aa8a920c91760d8b",
    "name": "Numan",
    "favfriend":"d8930c49405242d5923362b8818b93ad"
  }'
);
use castfriends;
CREATE TABLE `friends` (
  `uid` int NOT NULL AUTO_INCREMENT COMMENT 'id',
  `crew` json DEFAULT NULL COMMENT 'supporting fields for parent',
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb3;

insert into castfriends.friends (crew)  values 
(
  '{
    "guid" : "d8930c49405242d5923362b8818b93ad",
    "screen": "Rachel"
  }'
),
(
  '{
    "guid" : "49578c5a85a1454597b911e8c6300828",
    "screen": "Monica"
  }'
),
(
  '{
    "guid" : "a846ec1c09844012bb1d3e64ae311bf8",
    "screen": "Ursula"
  }'
),
(
  '{
    "guid" : "c1fcb509e6b34e5ba5d0a44329a88a94",
    "screen": "Ross"
  }'
),
(
  '{
    "guid" : "062a55f932ea408e8f8f1914f1499a24",
    "screen": "Gina"
  }'
);

CodePudding user response:

You have a WHERE clause before a LEFT JOIN. It needs to come after...

  • SELECT ... FROM ... JOIN ... WHERE ... GROUP BY ... ORDER BY ...

CodePudding user response:

Parse your JSONs to separate columns:

SELECT people.uid, p_details.*
FROM people
CROSS JOIN JSON_TABLE( people.details,
                       '$' COLUMNS ( guid CHAR(32) PATH '$.guid',
                                     name VARCHAR(255) PATH '$.name',
                                     favfriend CHAR(32) PATH '$.favfriend' 
                                    )
                      ) p_details;

SELECT friends.uid, f_details.*
FROM friends
CROSS JOIN JSON_TABLE( friends.crew ,
                       '$' COLUMNS ( guid CHAR(32) PATH '$.guid',
                                     screen VARCHAR(255) PATH '$.screen'
                                    )
                      ) f_details;

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ea67858bd8abae43d73224c818ee58d2

Using these queries as CTEs join them in outer query, apply any needed conditions, then reconstruct desired final JSON values and use in UPDATE.

  • Related