MySQL JSON объединение двух json объектов первичного ключа в JSON документе - PullRequest
1 голос
/ 09 марта 2020

У меня есть JSON столбец, в котором хранится документ. Я хочу выполнить атомы c ОБНОВЛЕНИЯ для этого столбца.

Дано, например, значение:

[{"substanceId": 182, "text": "substance_name_182"}, {"substanceId": 183, "text": "substance_name_183"}]

и обновление

[{"substanceId": 182, "text": "substance_name_182_new"}, {"substanceId": 184, "text": "substance_name_184"}]

Я ожидаю получить это:

[{"substanceId": 182, "text": "substance_name_182_new"}, {"substanceId": 183, "text": "substance_name_183"} {"substanceId": 184, "text": "substance_name_184"}}]

Ни один из JSON_MERGE_PATCH или JSON_MERGE_PRESERVE напрямую не позволяет мне достичь этого. JSON_MERGE_PATCH не знает, substanceId является идентификатором документа. Есть ли способ достичь этого на стороне MySQL? Я мог бы сделать это на стороне клиента (сначала получить значение, изменить и обновить его), но это в крайнем случае, во-первых, у меня есть множество строк для обновления, где все они будут охвачены UPDATE с предложением WHERE, поэтому способ MySQL был бы более удобным. Когда вы делаете это на стороне клиента и делаете это безопасно, мне придется заблокировать много строк НА ОБНОВЛЕНИЕ.

Например, запрос:

SELECT JSON_MERGE_PATCH(
'[{"substanceId": 182, "text": "substance_name_182"}, {"substanceId": 183, "text": "substance_name_183"}]',
'[{"substanceId": 182, "text": "substance_name_182_new"}, {"substanceId": 184, "text": "substance_name_184"}]'
) v;

результаты

[{"text": "substance_name_182_new", "substanceId": 182}, {"text": "substance_name_184", "substanceId": 184}]

1 Ответ

2 голосов
/ 09 марта 2020

Вот безумно запутанный способ сделать это в MySQL, используя JSON_TABLE для преобразования обновления и исходных значений JSON в столбцы, объединяя столбцы с помощью (смоделированного) FULL JOIN и затем воссоздание выходного значения JSON с использованием JSON_OBJECT и JSON_ARRAYAGG; наконец, используя это для обновления исходной таблицы:

WITH upd AS (
  SELECT *
  FROM JSON_TABLE('[{"substanceId": 182, "text": "substance_name_182_new"}, {"substanceId": 184, "text": "substance_name_184"}]',
                  '$[*]' COLUMNS (
                  substanceId INT PATH '$.substanceId',
                  txt VARCHAR (100) PATH '$.text')
                  ) jt
  CROSS JOIN (SELECT DISTINCT id
              FROM test) t
),
cur AS (
  SELECT id, substanceId, txt
  FROM test
  JOIN JSON_TABLE(test.j,
                  '$[*]' COLUMNS (
                  substanceId INT PATH '$.substanceId',
                  txt VARCHAR (100) PATH '$.text')
                 ) jt
),
allv AS (
  SELECT COALESCE(upd.id, cur.id) AS id, 
         COALESCE(upd.substanceId, cur.substanceId) AS substanceId,
         COALESCE(upd.txt, cur.txt) AS txt
  FROM upd
  LEFT JOIN cur ON cur.substanceId = upd.substanceId
  UNION ALL 
  SELECT COALESCE(upd.id, cur.id) AS id, 
         COALESCE(upd.substanceId, cur.substanceId) AS substanceId,
         COALESCE(upd.txt, cur.txt) AS txt
  FROM upd
  RIGHT JOIN cur ON cur.substanceId = upd.substanceId
),
obj AS (
  SELECT DISTINCT id, JSON_OBJECT('substanceId', substanceId, 'text', txt) AS o
  FROM allv
),
arr AS (
  SELECT id, JSON_ARRAYAGG(o) AS a
  FROM obj
  GROUP BY id
)
UPDATE test
JOIN arr ON test.id = arr.id
SET test.j = arr.a
;
SELECT JSON_PRETTY(j)
FROM test

Вывод:

[
  {
    "text": "substance_name_183",
    "substanceId": 183
  },
  {
    "text": "substance_name_184",
    "substanceId": 184
  },
  {
    "text": "substance_name_182_new",
    "substanceId": 182
  }
]

Демонстрация на dbfiddle

Обратите внимание, что предполагается, что вы используете уникальное id значение для различения guish строк в вашей таблице. Если вы используете что-то другое, вам нужно поменять его там, где id используется в приведенном выше запросе.

...