UNION ALL для типа данных JSON

Мне нужно UNION ALL столбец JSON в Postgres 9.2. Но Postgres отвечает этой ошибкой:

ERROR: could not identify an equality operator for type json SQL  
state: 42883  
Character: 9

На запрос:

(select cast('{"billingcode" : "' || billingcode || '"}' as JSON)
 from billing_2012_08 limit 10)
union
(select cast('{"charged" : "' || charged || '"}' as JSON)
 from sending_response_2012_08 limit 10)

Что здесь не так?

Кажется, в Postgres нет оператора равенства для типа данных json.
Если это правильно, то почему?

В качестве примера, пытаясь выяснить проблему, это отлично работает:

(select cast('{"billingcode" : "' || billingcode || '"}' as JSON)
 from billing_2012_08 limit 10)
union all
(select cast('{"charged" : "' || charged || '"}' as JSON)
 from sending_response_2012_08 limit 10)

Обратите внимание, что UNION ALL просто «добавляет» результаты, а не просто UNION, который устраняет повторяющиеся значения.


person Diego Andrés Díaz Espinoza    schedule 16.09.2013    source источник


Ответы (1)


Проверить, равны ли значения JSON, непросто. Помимо прочего, атрибуты могут быть отсортированы в любом порядке, или может быть любое количество незначительных пробелов. Таким образом, двоичное или текстовое представление может быть совершенно другим, в то время как значение по-прежнему считается равным согласно спецификациям JSON. Вот почему для типа данных не существует оператора равенства. json в PostgreSQL.

Если вы удовлетворены тем, что текстовые представления равны (как видно из примера), вы можете UNION ALL со столбцом text и привести к json позже:

SELECT json_col::json
FROM (
   (SELECT '{"billingcode" : "' || billingcode || '"}'::text AS json_col
    FROM   billing_2012_08 LIMIT 10)
   UNION ALL
   (SELECT '{"charged" : "' || charged || '"}'::text
    FROM   sending_response_2012_08 LIMIT 10)
   ) sub

Или вы можете использовать jsonb в Postgres 9.4 или более поздних версиях, который поставляется с отсутствующим ранее оператором равенства (среди прочего). Видеть:

Затем рассмотрите этот альтернативный запрос:

SELECT to_jsonb(t) AS jsonb_col
FROM  (SELECT billingcode FROM billing_2012_08 LIMIT 10) t

UNION
SELECT to_jsonb(t)   -- also preserves possible numeric type!
FROM  (SELECT charged FROM sending_response_2012_08 LIMIT 10) t

ORDER  BY 1;  -- possible with jsonb

В дополнение к UNION теперь также возможен ORDER BY.

Обратите внимание на использование to_jsonb(). При подаче строки имена столбцов автоматически используются в качестве имен ключей. Это чище и быстрее и (среди прочего) сохраняет возможные числовые типы, которые могут повлиять на равенство и порядок сортировки. (также доступен to_json(). )

db‹›fiddle здесь
Старый sqlfiddle

person Erwin Brandstetter    schedule 16.09.2013