Get the default values of table columns in Postgres?

前端 未结 6 1983
温柔的废话
温柔的废话 2020-11-29 11:21

I\'m looking for a way to run a query to find the default values of the columns of a table in Postgres. For example, if I made a table with the following query:

相关标签:
6条回答
  • 2020-11-29 11:21

    you can just type " \d table_name" command , then It will displays some information about the table, such as the default value of a column.

    --create table

    skytf=> CREATE TABLE mytable (
    skytf(>     a integer DEFAULT 2,
    skytf(>     b varchar(64)  DEFAULT 'I am default',
    skytf(>     c varchar(64)  DEFAULT 'I am also default'
    skytf(> );
    CREATE TABLE
    

    --show table information

    skytf=> \d mytable
                                  Table "skytf.mytable"
     Column |         Type          |                   Modifiers                    
    --------+-----------------------+------------------------------------------------
     a      | integer               | default 2
     b      | character varying(64) | default 'I am default'::character varying
     c      | character varying(64) | default 'I am also default'::character varying
    
    0 讨论(0)
  • 2020-11-29 11:29

    I'm spending some time trying to get to grips with the pg_catalog tables. I'm assuming the names and such come back from the days when letters had to be carved individually and were, consequently, very expensive ;-) Anyway, that's all a fact of life. I wanted to get the default value for a column and ran into this thread. I saw a mention of wanting to have Erwin Brandstetter's code as a function. I've wrapped it up and figured I'd add it to the archives:

    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;
    

    I'm using the code (probably in an inhumane manner) like so:

    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)
    

    From here I figure I'll write a view, etc., once I know better what I'm really after. For now, I'm using a CTE as a temporary view:

    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'
    

    Corrections, improvements, and suggestions all welcome...I'm just getting my feet wet in pg_catalog.

    0 讨论(0)
  • I liked Erwin's Answer but was having some difficulties:

    1. Sometimes I would get column names "........pg.dropped.30.......", etc. even with the NOT a.attisdropped qualification. It was not consistent, I wound up having to loop through the results and check the column names.
    2. The returned default value sometimes had a cast attached, e.g. 'I am default'::character varying which did not work when they are being stuffed into web form input values. I could not think of a good way to remove the cast suffix without doing something like .replace(/::.*/, '') which is not robust enough. I bet Erwin can figure out some magical way to EVAL() the returned value and use the a.atttypid column to get the right data type.

    So I went back to what I was doing before:

    BEGIN;
    INSERT INTO mytable DEFAULT VALUES RETURNING *;
    ROLLBACK;
    

    One thing to note here is that any SERIAL columns will get incremented. It likely does not matter so long as it is unique if it is just a table index. Otherwise it is a deal breaker.

    The other thing to watch out for is any TRIGGER AFTER/BEFORE INSERT which will fire even though the INSERT gets rolled back (I think any changes the trigger function makes will get rolled back though.)

    0 讨论(0)
  • 2020-11-29 11:45

    System catalogs are the source of truth in 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';
    
    • Related answer on dba.SE discussing information schema vs. system catalogs

    LEFT JOIN guarantees a result as long as the column exists. If there is no default you get NULL - which happens to be the default default. And almost always correct. But see:

    • How to use default value of data type as column default?

    To exclude columns without default, use JOIN instead and be prepared to get no row occasionally.

    The special cast ::regclass considers the current setting for search_path. With names that aren't schema-qualified (which you should, to be sure!), you may or may not get the expected result. See rebuttal below. More in the manual. Related:

    • How does the search_path influence identifier resolution and the "current schema"

    No need to include pg_class once we have the OID of the table. Faster without.

    Why the first answer wouldn't do

    @Zohaib's query is almost but not quite right. There are a couple of issues. I copied it here for future reference. Do not use this:

    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
    
    • Copied from some blog. Good that it's mentioned, but the source should be added. People reading that blog need to be warned.

    • Typo in pg_atttribute - fixed easily.

    • Doesn't return any rows, if there is no default specified for the requested column. Better make that a LEFT JOIN pg_attrdef ON .., so you always get a resulting row if the column exists. It will be NULL, if there is no default, which is actually the correct result because NULL is the default then.

    • If you remove attname from the WHERE clause, you only get values for columns that actually have a default value. Not for others. And you need to add attname to the SELECT list or you will not know for which column.

    • The query would also return the default of a column that is already dropped, which is wrong. Read about the details in the manual.

    • Most importantly: the query can give completely wrong results, as it does not take the schema name into account. There can be any number of table1.col1 in a postgres database: in various schemas. If more than one have a default, you get multiple values. If the column you have in mind does not have a default, but another one in another schema does, you will be fooled and never know it.

    • Last not least: in recent PostgreSQL releases, the adsrc column has been removed from pg_attrdef by commit fe5038236c, as it was redundant, deprecated and unused in PostgreSQL.

    To sum it up: C/P from some blog without insight went dangerously wrong.

    0 讨论(0)
  • 2020-11-29 11:48

    Use the information schema:

    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)
    

    Up to the schema naming, this should work in any SQL database system.

    0 讨论(0)
  • 2020-11-29 11:48
     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
    

    I found this query for postgresql on one of the blogs. you can try this to check if it works. To get values of all coumns, you can try removing AND pat.attname='your_column_name' from where clause.

    0 讨论(0)
提交回复
热议问题