Обновление целочисленного столбца из члена jsonb завершается неудачно с помощью: column имеет тип integer, но выражение имеет тип jsonb
В таблице PostgreSQL 9.5 у меня есть integer
колонка social
,
Когда я пытаюсь обновить его в хранимой процедуре, учитывая следующие данные JSON (массив с 2 объектами, каждый из которых имеет "социальный" ключ) в in_users
переменная типа jsonb
:
'[{"sid":"12345284239407942","auth":"ddddc1808197a1161bc22dc307accccc",**"social":3**,"given":"Alexander1","family":"Farber","photo":"https:\/\/graph.facebook.com\/1015428423940942\/picture?type=large","place":"Bochum, Germany","female":0,"stamp":1450102770}, {"sid":"54321284239407942","auth":"ddddc1808197a1161bc22dc307abbbbb",**"social":4**,"given":"Alxander2","family":"Farber","photo":null,"place":"Bochum, Germany","female":0,"stamp":1450102800}]'::jsonb
Тогда следующий код не работает:
FOR t IN SELECT * FROM JSONB_ARRAY_ELEMENTS(in_users)
LOOP
UPDATE words_social SET
social = t->'social',
WHERE sid = t->>'sid';
END LOOP;
с сообщением об ошибке:
ERROR: column "social" is of type integer but expression is of type jsonb
LINE 3: social = t->'social',
^
HINT: You will need to rewrite or cast the expression.
Я попытался изменить эту строку на:
social = t->'social'::int,
но тогда я получаю ошибку:
ERROR: invalid input syntax for integer: "social"
LINE 3: social = t->'social'::int,
^
Почему PostgreSQL не признает, что данные integer
?
Из таблицы JSON-TYPE-MAPPING-TABLE у меня сложилось впечатление, что число JSON будет автоматически преобразовано в числовой тип PostgreSQL.
2 ответа
Отдельная команда SQL на основе набора гораздо более эффективна, чем зацикливание:
UPDATE words_social w
SET social = (iu->>'social')::int
FROM JSONB_ARRAY_ELEMENTS(in_users) iu -- in_user = function variable
WHERE w.sid = iu->>'sid'; -- type of sid?
Чтобы ответить на ваш оригинальный вопрос:
Почему PostgreSQL не распознает, что данные целочисленные?
Потому что вы пытались преобразовать jsonb
значение для integer
, В своем решении вы уже обнаружили, что вам нужно ->>
оператор вместо ->
извлекать text
, который может быть приведен к integer
,
Ваша вторая попытка добавила вторую ошибку:
t->'social'::int
В дополнение к вышесказанному: приоритет оператора. Оператор броска ::
связывает сильнее, чем оператор JSON ->
, Как вы уже нашли себя, вы действительно хотите:
(t->>'social')::int
Очень похожий случай на dba.SE:
Я закончил тем, что использовал:
FOR t IN SELECT * FROM JSONB_ARRAY_ELEMENTS(in_users)
LOOP
UPDATE words_social SET
social = (t->>'social')::int
WHERE sid = t->>'sid';
IF NOT FOUND THEN
INSERT INTO words_social (social)
VALUES ((t->>'social')::int);
END IF;
END LOOP;