以下の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
キャストするだけ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
そして、その型の配列が定義済みの型で提供されていないことが起こります。
テーブル名は一意の識別子ではありません。同じ名前のテーブルが別のスキーマに存在する可能性があります。
スキーマ修飾せずにクエリでテーブル名を使用することは問題なく動作する可能性があります。 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
);