PostgreSQL - 列名

时间:2016-09-12 00:38:34

标签: postgresql plpgsql dynamic-sql

我希望在PostgreSQL中从一个表动态插入一组列到另一个表。我想我想做的是在列标题的'核对表'中读取(表1中存在的那些列 - 存储表),如果它们存在于导出表(表2)中,则将它们插入所有列表2将在其列中变量 - 一旦导入,则删除它并导入要导入的具有可能不同列结构的新数据。所以我需要根据列名称导入它。

e.g。

表1. - 存储表

ID     NAME     YEAR     LITH_AGE    PROV_AGE    SIO2    TIO2    CAO    MGO   COMMENTS
1      John     1998     2000        3000        65      10      5      5     comment1
2      Mark     2005     2444        3444        63      8       2      3     comment2
3      Luke     2001     1000        1500        77      10      2      2     comment3

表2. - 导出表

ID     NAME     MG#    METHOD    SIO2    TIO2    CAO    MGO
1      Amy      4      Method1   65      10      5      5    
2      Poe      3      Method2   63      8       2      3   
3      Ben      2      Method3   77      10      2      2     

正如您所看到的,导出表可能包含存储表中不存在的列,因此这些列将被忽略。

我想一次性插入所有这些列,因为我发现如果我按列单独执行它会在插入时每次扩展行数(也许有人可以解决这个问题?目前我已经编写了一个函数来检查表2中是否存在列名,如果存在,则插入它,但如上所述,这样每次都会扩展表的行,而其余列则为NULL)。 我函数的INSERT行:

EXECUTE format('INSERT INTO %s (%s) (SELECT %s::%s FROM %s);',_tbl_import, _col,_col,_type,_tbl_export);

作为我的问题的一种“代码示例”:

EXECUTE FORMAT('INSERT INTO table1 (%s) (SELECT (%s) FROM table2)',columns)

其中'columns'是一些变量,表示导出表中存在的需要进入存储表的列。这将是可变的,因为表2每次都会有所不同。

理想情况下,将表1更新为:

ID     NAME     YEAR     LITH_AGE    PROV_AGE    SIO2    TIO2    CAO    MGO   COMMENTS
1      John     1998     2000        3000        65      10      5      5     comment1
2      Mark     2005     2444        3444        63      8       2      3     comment2
3      Luke     2001     1000        1500        77      10      2      2     comment3
4      Amy      NULL     NULL        NULL        65      10      5      5     NULL
5      Poe      NULL     NULL        NULL        63      8       2      3     NULL   
6      Ben      NULL     NULL        NULL        77      10      2      2     NULL  

1 个答案:

答案 0 :(得分:0)

更新回答

由于我原来的答案不符合要求后来出来,但被要求发布一个信息解决方案的另一个例子,所以在这里。

我为解决方案制作了两个版本:

V1 - 等同于使用 information_schema 已经给出的示例。但该解决方案依赖于 table1 DEFAULT 。这意味着,如果 table2 中不存在的 table1 列没有 DEFAULT NULL ,那么它将填充默认值。

V2 - 被修改为强制“空白”'如果两个表列不匹配并且没有继承 table1 自己的DEFAULTs

<强>版本1:

CREATE OR REPLACE FUNCTION insert_into_table1_v1()
RETURNS void AS $main$

DECLARE
    columns text;

BEGIN

    SELECT  string_agg(c1.attname, ',')
    INTO    columns
    FROM    pg_attribute c1
    JOIN    pg_attribute c2
    ON      c1.attrelid = 'public.table1'::regclass
    AND     c2.attrelid = 'public.table2'::regclass
    AND     c1.attnum > 0
    AND     c2.attnum > 0
    AND     NOT c1.attisdropped
    AND     NOT c2.attisdropped
    AND     c1.attname = c2.attname
    AND     c1.attname <> 'id';

    --       Following is the actual result of query above, based on given data examples:
    --       -[ RECORD 1 ]----------------------
    --       string_agg | name,si02,ti02,cao,mgo

    EXECUTE format(
        '   INSERT INTO table1 ( %1$s )
            SELECT %1$s
            FROM table2
        ',
        columns
    );

END;
$main$ LANGUAGE plpgsql;

<强>版本2:

CREATE OR REPLACE FUNCTION insert_into_table1_v2()
RETURNS void AS $main$

DECLARE
    t1_cols text;
    t2_cols text;

BEGIN

    SELECT  string_agg( c1.attname, ',' ),
            string_agg( COALESCE( c2.attname, 'NULL' ), ',' )
    INTO    t1_cols,
            t2_cols
    FROM    pg_attribute c1
    LEFT JOIN    pg_attribute c2
    ON      c2.attrelid = 'public.table2'::regclass
    AND     c2.attnum > 0
    AND     NOT c2.attisdropped
    AND     c1.attname = c2.attname
    WHERE   c1.attrelid = 'public.table1'::regclass
    AND     c1.attnum > 0
    AND     NOT c1.attisdropped
    AND     c1.attname <> 'id';

    --       Following is the actual result of query above, based on given data examples:
    --                               t1_cols                         |                  t2_cols
    --       --------------------------------------------------------+--------------------------------------------
    --        name,year,lith_age,prov_age,si02,ti02,cao,mgo,comments | name,NULL,NULL,NULL,si02,ti02,cao,mgo,NULL
    --       (1 row)

    EXECUTE format(
        '   INSERT INTO table1 ( %s )
            SELECT %s
            FROM table2
        ',
        t1_cols,
        t2_cols
    );

END;
$main$ LANGUAGE plpgsql;

如果不明确的话,还链接到有关 pg_attribute 表格列的文档:https://www.postgresql.org/docs/current/static/catalog-pg-attribute.html

希望这有助于:)