Поведение NOT LIKE со значениями NULL

Я хочу получить все столбцы таблицы, кроме столбцов последовательного типа. Самый близкий запрос к этой проблеме, который я смог придумать:

SELECT column_name FROM information_schema.columns
WHERE table_name = 'table1' AND column_default NOT LIKE 'nextval%'

Но проблема в том, что он также исключает/фильтрует строки, имеющие пустые значения для column_default. Я не знаю, почему поведение Postgres такое. Поэтому мне пришлось изменить свой запрос на что-то вроде этого:

SELECT column_name FROM information_schema.columns
WHERE table_name = 'table1'
AND ( column_default IS NULL OR column_default NOT LIKE 'nextval%')

Приветствуются любые лучшие предложения или обоснования этого.


person kushi    schedule 02.04.2014    source источник
comment
Сравнение с NULL без использования IS NULL или IS NOT NULL возвращает NULL вместо true или false в большинстве/во всех системах баз данных.   -  person Sam DeHaan    schedule 02.04.2014


Ответы (2)


О NULL

'anything' NOT LIKE NULL дает NULL, а не TRUE.
И только TRUE подходит для выражений фильтра в предложении WHERE.

Большинство функций возвращают NULL при вводе NULL (есть исключения). Такова природа NULL в любой правильной СУБД.

Если вам нужно одно выражение, вы можете использовать:

AND   (column_default LIKE 'nextval%')  IS NOT TRUE;

Однако вряд ли это короче или быстрее. Подробности в руководстве.

Правильный запрос

Ваш запрос по-прежнему ненадежен. Само по себе имя таблицы не является уникальным в базе данных Postgres, вам нужно дополнительно указать имя схемы или полагаться на текущий search_path, чтобы найти в нем первое совпадение:

Связанный:

SELECT column_name
FROM   information_schema.columns
WHERE  table_name = 'hstore1'
AND    table_schema = 'public'   -- your schema
AND   (column_default IS NULL OR
       column_default NOT LIKE 'nextval%');

Лучше, но все равно не пуленепробиваемый. Столбец по умолчанию, начинающийся с «nextval», еще не дает serial. Видеть:

Чтобы быть уверенным, проверьте, принадлежит ли используемая последовательность столбцу с pg_get_serial_sequence(table_name, column_name).

Сам я редко использую информационную схему. Эти медленные, раздутые представления гарантируют переносимость между основными версиями и нацелены на переносимость на другие РСУБД, соответствующие стандартам. Но слишком многое в любом случае несовместимо. Oracle даже не реализует информационную схему (по состоянию на 2015 год).

Кроме того, в информационной схеме отсутствуют полезные столбцы, специфичные для Postgres. В этом случае я мог бы запросить системные каталоги следующим образом:

SELECT *
FROM   pg_catalog.pg_attribute a
WHERE  attrelid = 'table1'::regclass
AND    NOT attisdropped   -- no dropped (dead) columns
AND    attnum > 0         -- no system columns
AND   NOT EXISTS (
   SELECT FROM pg_catalog.pg_attrdef d
   WHERE  (d.adrelid, d.adnum) = (a.attrelid, a.attnum)
   AND    d.adsrc LIKE 'nextval%'
   AND    pg_get_serial_sequence(a.attrelid::regclass::text, a.attname) <> ''
   );

Быстрее и надежнее, но менее портативно.

Руководство:

В каталоге pg_attrdef хранятся значения столбцов по умолчанию. Основная информация о столбцах хранится в pg_attribute (см. ниже). Только столбцы, в которых явно указано значение по умолчанию (при создании таблицы или добавлении столбца), будут иметь здесь запись.

'table1'::regclass использует search_path для разрешения имени, что позволяет избежать двусмысленности. Вы можете квалифицировать имя схемы для отмены: 'myschema.table1'::regclass.

Связанный:

person Erwin Brandstetter    schedule 02.04.2014
comment
Я действительно хотел бы, чтобы они изменили стандарт, чтобы иметь смысл. NULL означает отсутствие значения, а это означает, что LIKE и NOT LIKE должны фактически оцениваться как FALSE и TRUE соответственно при работе со значениями NULL, а не с бессмысленным NULL. - person Tom Lint; 15.02.2019

Я думаю, вы можете использовать:

SELECT column_name *FROM* information_schema.columns
WHERE table_name = 'table1'
AND ( nvl(column_default,0) *NOT LIKE* 'nextval%');
person satish pattar    schedule 15.01.2016
comment
Пожалуйста, добавьте некоторые пояснения к вашему ответу! - person Mattias Lindberg; 15.01.2016
comment
Функция nvl/coalesce даст значение для поля column_default, чтобы оно не было нулевым. похоже, это работает, и им проще управлять, чем добавлять дополнительные параметры предложения where. - person jgaw; 23.11.2016