web-dev-qa-db-ja.com

エラー:データ型information_schema.sql_identifierの配列型が見つかりませんでした

以下のSQLコマンドを実行しようとしています:

SELECT ARRAY(
    SELECT column_name 
    FROM information_schema.columns 
    WHERE table_name ='gis_field_configuration_stage'
);

そして私は以下のエラーを受け取ります:

ERROR:  could not find array type for datatype information_schema.sql_identifier
3
John Mitchell

キャストするだけcolumn_name to text to the bypass the error:

SELECT ARRAY(
    SELECT column_name::text
    FROM information_schema.columns 
    WHERE table_name ='gis_field_configuration_stage'
);

元の型はinformation_schema.sql_identifierそして、その型の配列が定義済みの型で提供されていないことが起こります。

6
Daniel Vérité

テーブル名は一意ではありません

テーブル名は一意の識別子ではありません。同じ名前のテーブルが別のスキーマに存在する可能性があります。

スキーマ修飾せずにクエリでテーブル名を使用することは問題なく動作する可能性があります。 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
)

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
);

私のテストでは、約100倍速くなりました。

regclassへのキャストは確実です

これにはもう1つの重要な利点があります。テーブル名を誤って入力した場合、または最初のクエリで他の理由でテーブル名が存在しない場合は、列が見つかりません。結果は誤解を招く可能性があり、あなたはそれを知ることは決してないでしょう。私が示すように('public.tbl'::regclass)のようにテーブルをキャストすると、テーブルが存在してはならない場合にエラーメッセージが表示されます。 マニュアルのオブジェクト識別子タイプの詳細。

'tbl'::regclassはこの式の評価に使用されるため、search_pathを使用することもできます。基本クエリがスキーマ修飾なしで機能する場合、これも機能します。スキーマを追加する方が安全です。

関連:

無効なクエリ

コメントのアプローチはinvalidです。
ARRAY[...] NOT IN ARRAY[...]はPostgresでは意味がありません。

2つのテーブルを確認したい場合any列名を共有しない

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
   );

2つのテーブルを確認したい場合all列名を共有しない

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
   );
4