Тип данных столбца 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
Исключает нарушающие строки из запроса.
Связанные с: