MySQL — экранирование двойных кавычек и скобок при запросе столбца JSON

#mysql #json

#mysql #json

Вопрос:

как избежать двойных кавычек и скобок при запросе столбца JSON, содержащего массив объектов?

Это работает, когда я его запускаю…

 SELECT boarded, boarded->>"$[0].division.id" AS divisionId FROM onboarder
  

Но это не так…

 SELECT boarded, boarded->>"$[*].division.id" AS divisionId FROM onboarder
  

Я думал, что двойные стрелки экранировали все и вернули только значение. Это то, что у меня есть…

введите описание изображения здесь

Ответ №1:

->> Оператор ничего не экранирует. Он просто преобразует результат в скалярный тип данных, такой как text или integer . Это эквивалентно выполнению JSON_UNQUOTE(JSON_EXTRACT(…)):

Выводит значение JSON из кавычек и возвращает результат в виде строки utf8mb4.

Мы можем продемонстрировать разницу между -> и ->> , используя набор результатов для создания новой таблицы и проверяя типы данных, которые она создает.

 create table t as SELECT boarded, boarded->"$[*].division.id" AS divisionId FROM onboarder;

show create table t;
CREATE TABLE `t` (
  `boarded` json DEFAULT NULL,
  `divisionId` json DEFAULT NULL
);

select * from t;
 ------------------------------------ -------------- 
| boarded                            | divisionId   |
 ------------------------------------ -------------- 
| [{"division": {"id": "8ac7a..."}}] | ["8ac7a..."] |
 ------------------------------------ -------------- 
  

Обратите внимание, что divisionId — это документ json, представляющий собой массив.

Если мы используем ->> это то, что происходит:

 create table t as SELECT boarded, boarded->>"$[*].division.id" AS divisionId FROM onboarder;

show create table t;

CREATE TABLE `t` (
  `boarded` json DEFAULT NULL,
  `divisionId` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
)

select * from t;
 ------------------------------------ -------------- 
| boarded                            | divisionId   |
 ------------------------------------ -------------- 
| [{"division": {"id": "8ac7a..."}}] | ["8ac7a..."] |
 ------------------------------------ -------------- 
  

Видимой разницы нет, потому что квадратные скобки все еще присутствуют. Но последний хранится как longtext тип данных.


Повторите свой комментарий:

Как я могу вернуть divisionId в качестве значения, чтобы оно не было массивом и не заключалось в кавычки?

Вы использовали $[*] в своем запросе, и смысл этого шаблона заключается в том, чтобы возвращать все элементы массива в виде массива. Чтобы получить единственное значение, вам нужно запросить один элемент массива, как в вашем первом примере:

 boarded->>'$[0].division.id'
  

Это было бы намного проще, если бы вы не использовали JSON, а хранили свои данные в традиционной таблице с одним разделением в отдельной строке и каждым полем разделения в своем собственном столбце.

 CREATE TABLE divisions (
  division_id VARCHAR(...) PRIMARY KEY,
  merchant ...
);

CREATE TABLE merchants (
  merchant_id ... PRIMARY KEY,
  division_id VARCHAR(...),
  FOREIGN KEY (division_id) REFERENCES division(division_id)
);
  

Чем больше примеров я вижу того, как разработчики пытаются использовать JSON в MySQL, тем больше я убежден, что это плохая идея.

Комментарии:

1. Спасибо за это объяснение. Как я могу вернуть divisionId в качестве значения, чтобы оно не было массивом и не заключалось в кавычки?

2. @Dally Using [*] означает, что вы хотите получить значение из каждого элемента массива. Как это будет возвращено в виде отдельной строки, а не массива?

3. @Barmar Каждая строка будет иметь только одно деление. В одном подразделении есть один продавец, который может содержать несколько каналов. Это мой рабочий процесс.

4. Тогда вам нужна как минимум таблица для подразделений и еще одна таблица для каналов.

5. Если у него может быть только одно деление, почему это массив? В любом случае, просто используйте [0] , чтобы получить один элемент массива. Или может быть несколько объектов, но только у одного из них есть division свойство?