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
は私の目的にとって重要ではなく、まったく問題ではありません。
情報スキーマを使用します。
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データベースシステムでも機能します。
システムカタログ は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が危険なほど間違っていました。
私は アーウィンの答え が好きでしたが、いくつかの困難を抱えていました:
NOT a.attisdropped
_修飾を使用しても、「........ pg.dropped.30 .......」などの列名が表示される場合があります。一貫性がなく、結果をループして列名を確認する必要がありました。'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
_は他にも注意する必要があります(トリガー関数による変更はすべてロールバックされると思います)。
私は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で足を濡らしています。