错误:找不到数据类型 information_schema.sql_identifier 的数组类型

Joh*_*ell 5 postgresql array catalogs

我正在尝试运行以下 sql 命令:

SELECT ARRAY(
    SELECT column_name 
    FROM information_schema.columns 
    WHERE table_name ='gis_field_configuration_stage'
);
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

ERROR:  could not find array type for datatype information_schema.sql_identifier
Run Code Online (Sandbox Code Playgroud)

Dan*_*ité 9

只需强制column_name转换text为绕过错误:

SELECT ARRAY(
    SELECT column_name::text
    FROM information_schema.columns 
    WHERE table_name ='gis_field_configuration_stage'
);
Run Code Online (Sandbox Code Playgroud)

它的原始类型是information_schema.sql_identifier并且碰巧在预定义类型中没有提供该类型的数组。


Erw*_*ter 5

表名不唯一

表名不是唯一标识符。同名的表可以存在于另一个模式中。

在查询中使用表名而不用模式限定它们可能会很好地工作。只要search_path设置正确,就会选择正确的桌子。

但这在查询目录表时不会有帮助!如果存在同名的其他表,您将取回所有这些表的所有列,甚至可能不会注意到它。添加架构名称以使其唯一:

SELECT ARRAY(
   SELECT column_name::text
   FROM   information_schema.columns 
   WHERE  table_name ='gis_field_configuration_stage'
   AND    table_schema ='public'  -- or whatever the schema is
)
Run Code Online (Sandbox Code Playgroud)

information_schema是慢的

information_schema仅适用于跨平台可移植性(无论如何都几乎不起作用)。里面的景色information_schema是巨大而缓慢的。如果您将来不打算将其移植到另一个 RDBMS,并且您不使用可能在 Postgres 版本之间发生变化的奇异功能,请改为使用pg_catalog.pg_attribute。Postgres 不会pg_attribute导致此等效查询无效的方式进行更改:

SELECT ARRAY(
   SELECT attname
   FROM   pg_catalog.pg_attribute
   WHERE  attrelid = 'public.tbl'::regclass
   AND    NOT attisdropped
   AND    attnum > 0
);
Run Code Online (Sandbox Code Playgroud)

在我的测试中大约快了100 倍

投射到regclass是肯定的

这还有另一个重要的优点:如果您输错了表名,或者在第一个查询中由于其他原因该表不存在,它就不会找到任何列。结果可能会产生误导,而且您永远不会知道。如果像我演示的那样转换表 ( 'public.tbl'::regclass),如果该表不应该存在,您会收到一条错误消息。手册中有关对象标识符类型的更多信息。

您甚至可以使用'tbl'::regclass,因为search_path用来计算该表达式。如果您的基本查询在没有架构限定的情况下也可以工作,那么这也可以。添加架构仍然更安全。

有关的:

无效查询

您评论中的方法一开始就是无效的。
ARRAY[...] NOT IN ARRAY[...]在 Postgres 中没有意义。

如果您想确保两个表不共享任何列名

SELECT *
FROM   tbl
WHERE  NOT EXISTS (
   SELECT 1
   FROM   pg_catalog.pg_attribute a1
   JOIN   pg_catalog.pg_attribute a2 USING (attname)
   WHERE  a1.attrelid = 'public.tbl'::regclass
   AND    NOT a1.attisdropped
   AND    a1.attnum > 0
   AND    a2.attrelid = 'public.tbl2'::regclass
   AND    NOT a2.attisdropped
   AND    a2.attnum > 0
   );
Run Code Online (Sandbox Code Playgroud)

如果您想确保两个表不共享所有列名

SELECT *
FROM   tbl
WHERE  EXISTS (
   SELECT 1
   FROM   (
      SELECT attname
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = 'public.tbl'::regclass
      AND    NOT attisdropped
      AND    attnum > 0
      ) a1
   FULL   OUTER JOIN (
      SELECT attname
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = 'public.tbl2'::regclass
      AND    NOT attisdropped
      AND    attnum > 0
      ) a2 USING (attname)
   WHERE  a1.attname IS NULL OR
          a2.attname IS NULL
   );
Run Code Online (Sandbox Code Playgroud)