Тип данных столбца peopleявляется json, как результат json_array_elements(people). И нет никакого оператора равенства ( =) для типа данных json. Таким образом, вы также не можете работать GROUP BYна нем. Больше:
jsonbимеет оператор равенства, поэтому «обходной путь» в вашем ответе - привести jsonbи использовать эквивалент jsonb_array_elements(). Состав добавляет стоимость:
jsonb_array_elements(people::jsonb)
Начиная с Postgres 9.4 мы также json_array_elements_text(json)возвращаем элементы массива как text. Связанные с:
Так:
SELECT p.name, count(*) AS c
FROM band b, json_array_elements_text(b.people) p(name)
GROUP BY p.name;
Кажется более удобным получать имена, поскольку textвместо jsonbобъектов (двойные кавычки в текстовом представлении) и ваш «желаемый вывод» указывает на то, что вы хотите / нуждаетесь textв результате для начала.
GROUP BYна textданных также дешевле, чем на jsonb, поэтому этот альтернативный «обходной путь» должен быть быстрее по двум причинам. (Тест с EXPLAIN (ANALYZE, TIMING OFF).)
Для протокола, в вашем первоначальном ответе не было ничего плохого . Запятая ( ,) так же «правильна», как и CROSS JOIN LATERAL. Будучи определенным ранее в стандартном SQL, не делает его хуже. Видеть:
Это и не более переносимый на другую СУБД, и так jsonb_array_elements()или json_array_elements_text()не переносимые на другую СУБД , чтобы начать с того , что это тоже не имеет значение. Короткий запрос не проясняется с CROSS JOIN LATERALИМО, но последний момент - только мое личное мнение.
Я использовал более явный псевдоним таблицы и столбца p(name)и ссылку на таблицу p.nameдля защиты от возможных повторяющихся имен. nameЭто такое общее слово, оно может также появиться как имя столбца в базовой таблице band, в этом случае он будет молча разрешить band.name. Простая форма json_array_elements_text(people) nameтолько присоединяет псевдоним таблицы , имя столбца остается value, как возвращено из функции. Но nameразрешается к одному столбцу valueпри использовании в SELECTсписке. Это работает, как ожидалось . Но истинное имя столбца name(если оно band.nameдолжно существовать) будет привязано первым. Хотя это не будет кусаться в данном примере, в других случаях это может быть заряженный ножной пистолет .
Не используйте общее имя в качестве идентификатора для начала. Может быть, это было просто для простого теста.
Если столбец peopleможет содержать что угодно, кроме простого массива JSON , любой запрос вызовет исключение. Если вы не можете гарантировать целостность данных, вы можете защитить json_typeof():
SELECT p.name, count(*) AS c
FROM band b, json_array_elements_text(b.people) p(name)
WHERE json_typeof(b.people) = 'array'
GROUP BY 1; -- optional short syntax since you seem to prefer short syntax
Исключает нарушающие строки из запроса.
Связанные с: