具有NULL值的NOT LIKE的行为

时间:2014-04-02 16:54:13

标签: sql postgresql null information-schema

我想获取除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 个答案:

答案 0 :(得分:15)

关于NULL

'anything' NOT LIKE NULL会产生NULL,而非TRUE 只有TRUE符合WHERE子句中的过滤表达式。

大多数函数在NULL输入上返回NULL(有例外)。这是任何适当的RDBMS中NULL的性质。

如果您需要单个表达式,可以使用:

AND   (column_default LIKE 'nextval%')  IS NOT TRUE;
但是,这几乎不会更短或更快。 Details in the manual.

正确查询

您的查询仍然不可靠。仅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)的列中。

我很少自己使用信息模式。这些缓慢,臃肿的视图保证了主要版本的可移植性 - 并且旨在实现其他符合标准的RDBMS的可移植性。但无论如何,太多是不相容的。 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) <> ''
   );

更快,更可靠,但便携性更低。

The manual:

  

目录pg_attrdef存储列默认值。主要的   有关列的信息存储在pg_attribute中(见下文)。只要   显式指定默认值的列(表格为时)   已创建或添加了列)将在此处输入一个条目。

'table1'::regclass使用search_path来解析名称,从而避免歧义。您可以对名称进行架构限定以取代:'myschema.table1'::regclass

相关:

答案 1 :(得分:-1)

.encode("utf-8")

也可以写

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

答案 2 :(得分:-2)

我认为你可以使用:

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