web-dev-qa-db-ja.com

Postgresのテーブル列のデフォルト値を取得しますか?

Postgresのテーブルの列のデフォルト値を見つけるクエリを実行する方法を探しています。たとえば、次のクエリでテーブルを作成したとします。

**編集者のメモ:質問には影響がないため、テーブルの定義を修正しました。

CREATE TABLE mytable (
    integer int DEFAULT 2,
    text varchar(64) DEFAULT 'I am default',
    moretext varchar(64) DEFAULT 'I am also default',
    unimportant int 
);

integerのデフォルトは2、textは「私はデフォルト」、moretextは「私はまた、デフォルトです。クエリ結果には、デフォルトのない他の列の値を含めることができます。つまり、unimportantは私の目的にとって重要ではなく、まったく問題ではありません。

22
sjchen

情報スキーマを使用します。

SELECT column_name, column_default
FROM information_schema.columns
WHERE (table_schema, table_name) = ('public', 'mytable')
ORDER BY ordinal_position;

 column_name │             column_default             
─────────────┼────────────────────────────────────────
 integer     │ 2
 text        │ 'I am default'::character varying
 moretext    │ 'I am also default'::character varying
 unimportant │ 
(4 rows)

スキーマの命名までは、これはどのSQLデータベースシステムでも機能します。

45

システムカタログ はPostgresの真実のソースです。

SELECT pg_get_expr(d.adbin, d.adrelid) AS default_value
FROM   pg_catalog.pg_attribute    a
LEFT   JOIN pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum) = (d.adrelid,  d.adnum)
WHERE  NOT a.attisdropped           -- no dropped (dead) columns
AND    a.attnum   > 0               -- no system columns
AND    a.attrelid = 'myschema.mytable'::regclass
AND    a.attname  = 'mycolumn';

LEFT JOINは、列が存在する限り結果を保証します。デフォルトがない場合は、NULL-defaultのデフォルトになります。そしてほとんど常に正しい。しかし参照してください:

デフォルトなしで列を除外するには、代わりにJOINを使用し、時々行を取得しないように準備します。

特別なキャスト::regclassは、search_pathの現在の設定を考慮します。スキーマで修飾されていない名前を使用すると(確かに!)、期待した結果が得られる場合と得られない場合があります。以下の反論を参照してください。 マニュアルの詳細。 関連:

テーブルのOIDがあれば、pg_classを含める必要はありません。

なぜ最初の答えがうまくいかないのか

@ Zohaibのクエリ はほぼ正しいですが、完全ではありません。いくつかの問題があります。後で参照できるように、ここにコピーしました。 これを使用しないでください

SELECT adsrc as default_value
 FROM pg_attrdef pad, pg_atttribute pat, pg_class pc
 WHERE pc.relname='your_table_name'
     AND pc.oid=pat.attrelid AND pat.attname='your_column_name'
     AND pat.attrelid=pad.adrelid AND pat.attnum=pad.adnum
  • いくつかのブログからコピーしました。それが言及されていることは良いが、ソースを追加する必要があります。そのブログを読む人々は警告される必要があります。

  • pg_atttributeのタイプミス-簡単に修正されました。

  • 要求された列にデフォルトが指定されていない場合、行を返しません。それがLEFT JOIN pg_attrdef ON ..になるようにすると、列が存在する場合は常にが結果の行を取得します。デフォルトがない場合はNULLになります。これは、NULLがデフォルトであるため、実際には正しい結果です。

  • WHERE句からattnameを削除すると、デフォルト値が実際にある列の値のみが取得されます。他の人のためではありません。また、attnameをSELECTリストに追加する必要があります。そうしないと、どの列が不明かがわかります。

  • クエリは、既に削除されている列のデフォルト、つまりwrongも返します。 マニュアルの詳細 について読んでください。

  • 最も重要なこと:クエリはスキーマ名を考慮しないため、クエリは完全に間違った結果を返す可能性があります。 postgresデータベースには、さまざまなスキーマのtable1.col1をいくつでも含めることができます。複数のデフォルトがある場合、複数の値を取得します。考えている列にデフォルトがないが、別のスキーマの別の列にある場合、だまされてそれを知ることはありません。

まとめると、洞察力のない一部のブログのC/Pが危険なほど間違っていました。

15

私は アーウィンの答え が好きでしたが、いくつかの困難を抱えていました:

  1. _NOT a.attisdropped_修飾を使用しても、「........ pg.dropped.30 .......」などの列名が表示される場合があります。一貫性がなく、結果をループして列名を確認する必要がありました。
  2. 返されたデフォルト値には、キャストが添付されていることがあります。 _'I am default'::character varying_は、Webフォームの入力値に詰め込まれているときに機能しませんでした。十分に堅牢ではない.replace(/::.*/, '')のようなことをせずにキャストサフィックスを削除する良い方法は考えられませんでした。 Erwinは EVAL() の戻り値に魔法のような方法を見つけ、_a.atttypid_列を使用して正しいデータ型を取得できると思います。

だから私は前にやっていたことに戻った:

_BEGIN;
INSERT INTO mytable DEFAULT VALUES RETURNING *;
ROLLBACK;
_

ここで注意すべきことの1つは、SERIAL列が増加することです。それが単なるテーブルインデックスである場合は、一意である限り問題ではありません。それ以外の場合は取引ブレーカーです。

INSERTがロールバックされても起動する_TRIGGER AFTER/BEFORE INSERT_は他にも注意する必要があります(トリガー関数による変更はすべてロールバックされると思います)。

1
user9645

私はpg_catalogテーブルを把握するために少し時間を費やしています。名前などは、文字を個別に刻む必要があり、その結果、非常に高額だった時代から戻ってきたと思います。列のデフォルト値を取得したかったので、このスレッドに遭遇しました。 Erwin Brandstetterのコードを関数として使用したいという言及がありました。私はそれをまとめて、アーカイブに追加すると思いました:

CREATE OR REPLACE FUNCTION data.column_default (qualified_name text, column_name text)
  RETURNS text
 AS $$

SELECT d.adsrc AS default_value -- A human-readable representation of the default value, already typed as text.
FROM   pg_catalog.pg_attribute a
LEFT   JOIN pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum)
                                     = (d.adrelid,  d.adnum)
WHERE  NOT a.attisdropped   -- no dropped (dead) columns
AND    a.attnum > 0         -- no system columns
AND    a.attrelid = qualified_name::regclass
AND    a.attname = column_name;

$$ LANGUAGE sql;

ALTER FUNCTION data.column_default (qualified_name text, column_name text) OWNER TO user_bender;

私はコードを(おそらく非人道的な方法で)次のように使用しています:

select pg_class.relnamespace::regnamespace as schema_name,
        attrelid::regclass as parent_name,
        attname,
       format_type(atttypid, atttypmod) as data_type,
       column_default(attrelid::regclass::text,attname),
       attnum

 from pg_attribute
 left join pg_class on (pg_class.oid = pg_attribute.attrelid::regclass)

ここから、自分が実際に何を求めているかがよくわかったら、ビューなどを記述します。今のところ、CTEを一時的なビューとして使用しています。

with attributes as
(select pg_class.relnamespace::regnamespace as schema_name,
        attrelid::regclass as parent_name,
        attname,
       format_type(atttypid, atttypmod) as data_type,
       column_default(attrelid::regclass::text,attname),
       attnum

 from pg_attribute
 left join pg_class on (pg_class.oid = pg_attribute.attrelid::regclass)
)

select *
  from attributes
 where parent_name::text = 'sales'

修正、改善、提案はすべて歓迎します... pg_catalogで足を濡らしています。

0
Morris de Oryx