Почему извлечение явного `null` в JSONB в виде текста дает SQL` null`? - PullRequest
2 голосов
/ 11 февраля 2020

Я пытаюсь понять обработку null с PostgreSQL jsonb типа. Из-за

# select 'null'::jsonb is null;
 ?column? 
----------
 f
(1 row)

Я предполагаю, что они отличаются от SQL null с (что имеет смысл) - в соответствии с руководством ,

SQL NULL - это другое понятие.

Поэтому эти два запроса совсем не удивительны:

# select '{"a": 1, "b": null}'::jsonb->'b' is null;
 ?column? 
----------
 f
(1 row)

# select '{"a": 1, "b": null}'::jsonb->'c' is null;
 ?column? 
----------
 t
(1 row)

за руководство :

Операторы извлечения поля / элемента / пути возвращают NULL, а не сбой, если вход JSON не имеет правильной структуры для соответствия запросу; например, если такого элемента не существует.

Где начинается сюрприз, однако, это:

# select '{"a": 1, "b": null}'::jsonb->>'b' is null;
 ?column? 
----------
 t
(1 row)

# select '{"a": 1, "b": null}'::jsonb->>'c' is null;
 ?column? 
----------
 t
(1 row)

Последний, который я могу понять - мы получаем SQL null от извлечения, и приведение null к text оставляет это как null - я предполагаю, что ->> работает таким образом, поскольку руководство говорит

Операторы извлечения поля / элемента / пути возвращают тот же тип, что и их левый ввод (либо json, либо jsonb), за исключением тех, которые указаны как возвращаемый текст, которые приводят значение к тексту.

(Кстати, я не смог найти подтверждения, что приведение SQL null к любому другому типу дает null снова в PostgreSQL - это написано где-то явно?)

Но первое для меня загадка Извлечение должно дать мне jsonb null, и я подумал, что приведение к text должно дать мне 'null' (т. Е. Строку, говорящую "null"), как

# select ('null'::jsonb)::text;
 text 
------
 null
(1 row)

Но все же он возвращает правильное значение SQL null.

Почему это так?

1 Ответ

1 голос
/ 12 февраля 2020

В какой-то степени это вопрос мнения разработчика; при преобразовании между JSON типами данных и SQL типами данных не всегда возможно найти идеальное соответствие, особенно если учесть, что SQL NULL настолько странен.

Но есть определенные логики c к тому, как это реализовано.

SELECT (JSONB '{"a": "null"}' -> 'a')::text,
       (JSONB '{"a": null}' -> 'a')::text;

  text  | text 
--------+------
 "null" | null
(1 row)

Приведение к text всегда дает результат, который при приведении к исходному типу производит исходное значение. Это принцип проектирования в PostgreSQL.

Так что JSON string "null" и JSON null будут приводиться к разным строкам.

Теперь посмотрим на это :

SELECT JSONB '{"a": "null"}' ->> 'a',
       JSONB '{"a": null}' ->> 'a';

 ?column? | ?column? 
----------+----------
 null     | 
(1 row)

Здесь, в отличие от приведенного выше акта, PostgreSQL пытается найти ближайший эквивалент значения JSON в SQL. Вы не хотели бы, чтобы строка "null" сохраняла свои двойные кавычки, потому что это была бы совсем другая строка в SQL, верно?

Но с другой стороны, это также не будет восприниматься правильно, если "null" и null были представлены одинаково в SQL, не так ли?

Насколько я знаю, JSON null означает «не там», и это одно из значений SQL NULL. Кроме того, наличие атрибута JSON со значением null означает то же самое, что и пропуск этого атрибута, не так ли?

Так что, хотя есть место для дискуссий, я думаю, что есть некоторая рифма и причина того, как это реализовано.

...