【问题标题】:Get the default values of table columns in Postgres?获取 Postgres 中表列的默认值?
【发布时间】:2011-12-30 02:14:53
【问题描述】:

我正在寻找一种方法来运行查询以查找 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 对我的目的来说并不重要,根本不重要。

【问题讨论】:

    标签: sql postgresql default


    【解决方案1】:

    使用信息架构:

    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 数据库系统。

    【讨论】:

    • 这行得通,但应该注意的是,如果性能是一个问题,这个查询很可能会比 Erwin 提供的答案更糟糕。
    • @a_horse_with_no_name 应该不是必须的
    【解决方案2】:

    System catalogs 是 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 的当前设置。使用不是模式限定的名称(当然,您应该这样做!),您可能会或可能不会获得预期的结果。见下文反驳。 More in the manual.相关:

    一旦我们有了表的 OID,就不需要包含 pg_class。没有更快。

    为什么第一个答案不行

    @Zohaib's query 几乎但不完全正确。有几个问题。我在这里复制它以供将来参考。 不要使用这个

    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 列表中,否则您将不知道是哪一列。

    • 查询还会返回已删除的列的默认值,这是错误。阅读details in the manual

    • 最重要的是:查询可能会给出完全错误的结果,因为它没有考虑架构名称。在 postgres 数据库中可以有任意数量的table1.col1:在各种模式中。如果多个有默认值,您将获得多个值。如果您想到的列没有默认值,但另一个模式中的另一个列有,那么您将被愚弄并且永远不知道。

    • 最后同样重要的是:在最近的 PostgreSQL 版本中,has been removed 来自 pg_attrdefadsrc 列由提交 fe5038236c,因为它在 PostgreSQL 中是多余的、已弃用和未使用的。

    总结一下:来自一些没有洞察力的博客的 C/P 出现了危险的错误。

    【讨论】:

    • 谢谢 - 非常有用,但我注意到即使使用 WHERE NOT a.attisdropped,您仍然偶尔会看到名为 "........pg.dropped.30........" 等的列。
    • 我想将此查询包装在一个函数中,但是该函数应该返回什么数据类型,因为返回的值将取决于所请求列的类型?
    • @ROBERTRICHARDSON:使用数据类型textpg_get_expression() 返回text。还要注意上面的一些更新。
    【解决方案3】:

    我喜欢Erwin's Answer,但遇到了一些困难:

    1. 有时我会得到列名“........pg.dropped.30.......”等,即使有NOT a.attisdropped 资格。不一致,我最终不得不遍历结果并检查列名。
    2. 返回的默认值有时会附加一个强制转换,例如'I am default'::character varying 在将它们填充到 Web 表单输入值中时不起作用。如果不执行 .replace(/::.*/, '') 之类的操作不够健壮,我想不出一个好方法来删除强制转换后缀。我敢打赌,Erwin 可以想出一些神奇的方法来 EVAL() 返回值,并使用 a.atttypid 列来获取正确的数据类型。

    于是我又回到了之前的工作:

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

    这里需要注意的一点是,任何SERIAL 列都会递增。如果它只是一个表索引,只要它是唯一的,它可能并不重要。否则会破坏交易。

    要注意的另一件事是任何TRIGGER AFTER/BEFORE INSERT,即使INSERT 被回滚(我认为触发器函数所做的任何更改都会被回滚)也会触发。

    【讨论】:

      【解决方案4】:

      我正在花一些时间尝试掌握 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 中沾沾自喜。

      【讨论】:

        【解决方案5】:
         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
        

        我在其中一个博客上找到了这个 postgresql 查询。你可以试试这个来检查它是否有效。要获取所有字段的值,您可以尝试从 where 子句中删除 AND pat.attname='your_column_name'

        【讨论】:

        • 错误:关系“pg_atttribute”不存在
        【解决方案6】:

        你可以输入“\d table_name”命令,然后它会显示一些关于 表,比如一列的默认值。

        --创建表

        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
        

        --显示表格信息

        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
        

        【讨论】:

        • 他询问如何查询默认值。这篇文章回答了一个没有被问到的问题。 (它的格式也很糟糕,但这与否决票无关)
        • \d 将显示列的默认值。我发布这个答案只是因为它比查询 pg_catalog 表或视图更容易。
        • 用户并不总是可以访问 psql 接口(例如,网络酒店客户)。因此 \d 并不总是可用,而 pg_catalog 是。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-07
        • 2012-11-27
        • 2017-09-27
        • 1970-01-01
        • 1970-01-01
        • 2016-12-22
        相关资源
        最近更新 更多