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

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

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%')

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

3 ответов


о NULL

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

большинство функций возвращают NULL on NULL input (есть исключения). Такова природа 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 для разрешения имени, что позволяет избежать двусмысленности. Вы можете schema-квалифицировать имя для отмены:'myschema.table1'::regclass.

по теме:


AND column_default NOT LIKE 'nextval%' OR column_default IS NULL

также можно написать

AND NOT column_default LIKE 'nextval%'

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

SELECT column_name *FROM* information_schema.columns
WHERE table_name = 'table1'
AND ( nvl(column_default,0) *NOT LIKE* 'nextval%');