web-dev-qa-db-ja.com

NULL値を使用したNOT LIKEの動作

シリアル型の列を除いて、テーブルのすべての列をフェッチしたい。この問題に最も近いクエリは、私がこれを思いつくことができました:

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

これの背後にあるより良い提案や理論的根拠は大歓迎です。

15
kushi

NULLについて

_'anything' NOT LIKE NULL_はNULLではなくTRUEを生成します。
そしてTRUE節のフィルター式に適格なのはWHEREだけです。

ほとんどの関数はNULL入力でNULLを返します(例外があります)。これがany適切なRDBMSにおける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) の列によって「所有されている」かどうかを確認します。

自分で情報スキーマを使用することはほとんどありません。これらの低速で肥大化したビューは、メジャーバージョン間の移植性を保証し、他の標準に準拠した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) <> ''
   );
_

高速で信頼性は高くなりますが、移植性は低下します。

マニュアル:

カタログ_pg_attrdef_は列のデフォルト値を格納します。列に関する主な情報は_pg_attribute_に格納されます(下記を参照)。 (テーブルが作成されたとき、または列が追加されたときに)デフォルト値を明示的に指定する列のみが、ここにエントリを持ちます。

_'table1'::regclass_は、_search_path_を使用して名前を解決し、あいまいさを回避します。名前をスキーマ修飾して却下できます:_'myschema.table1'::regclass_。

関連:

21