Postgresql 有没有一种简单的方法可以用默认值替换null?

Postgresql 有没有一种简单的方法可以用默认值替换null?,postgresql,Postgresql,我想将数据从一个表复制到另一个表中,但源表的列中可能有空值,而目标表不允许空值,但有默认值: drop table if exists table_with_nulls; create table table_with_nulls ( value1 integer, value2 integer ); insert into table_with_nulls values (1, null); drop table if exists table_with_defaults; c

我想将数据从一个表复制到另一个表中,但源表的列中可能有空值,而目标表不允许空值,但有默认值:

drop table if exists table_with_nulls;
create table table_with_nulls
(
    value1 integer,
    value2 integer
);
insert into table_with_nulls values (1, null);
drop table if exists table_with_defaults;
create table table_with_defaults
(
    value1 integer not null default 10,
    value2 integer not null default 20
);
insert into table_with_defaults (value1, value2)
select value1, value2 from table_with_nulls;
由于表_的null值为_nulls.value2,因此引发异常。是否有一种合理简单的方法可以为带有默认值的表\u获得20的值。值2?

示例表:

create table table_with_defaults
(
    value1 integer not null default 10,
    value2 numeric not null default 0.0,
    value3 text not null default '-- nothing --',
    value4 date not null default current_date,
    value5 text
);
您可以查询系统目录并查找表列的默认表达式:

select attname, adsrc
from pg_attribute a
left join pg_attrdef d on adrelid = attrelid and adnum = attnum
where attnum > 0
and attrelid = 'table_with_defaults'::regclass;

 attname |         adsrc         
---------+-----------------------
 value1  | 10
 value2  | 0.0
 value3  | '-- nothing --'::text
 value4  | ('now'::text)::date
 value5  | 
(5 rows)    
使用plpgsql函数中的查询生成并执行适当的语句:

create or replace function copy_table_with_defaults(table_from regclass, table_to regclass)
returns void language plpgsql as $$
declare
    column_list text;
begin

    select string_agg(
        case when adsrc is null then attname 
        else format('coalesce(%I, %s)', attname, adsrc) 
        end, ',')
    from pg_attribute a
    left join pg_attrdef d on adrelid = attrelid and adnum = attnum
    where attnum > 0
    and attrelid = table_to
    into column_list;

    execute format($ex$
        insert into %I
        select %s
        from %I
        $ex$, table_to, column_list, table_from);
end $$;
使用以下功能:

select copy_table_with_defaults('table_with_nulls'::regclass, 'table_with_defaults'::regclass);

非常感谢,@klin!我不得不稍微调整一下,因为我需要能够指定两个表的模式。以下是我的想法:

create or replace function conversion.copy_table_with_defaults_ex(schema_from text, table_from text, schema_to text, table_to text)
returns void language plpgsql as $$
declare
    column_list text;
begin
    select string_agg(
        case when adsrc is null then attname 
        else format('coalesce(%I, %s)', attname, adsrc) 
        end, ',')
    from pg_attribute a
    left join pg_attrdef d on adrelid = attrelid and adnum = attnum
    left join pg_class c on c.oid = a.attrelid
    left join pg_namespace ns on c.relnamespace = ns.oid
    where attnum > 0
    and c.relname = table_to
    and ns.nspname = schema_to
    into column_list;

    execute format($ex$
        insert into %I.%I
        select %s
        from %I.%I
        $ex$, schema_to, table_to, column_list, schema_from, table_from);
end $$;

如果没有更好的主意,请使用中间表,并将目标的所有空值更改为默认值。a>b,修复b,b>c。谢谢,但我不想假设我知道默认值。有些列可能具有常量默认值,有些列可能对序列使用nextval(),有些列可能是整数,有些列可能是文本,…没有内置的通用方法可以做到这一点<代码>合并()适用于任何类型。无论如何,我认为您无法创建具有未知约束的表。我不会创建具有未知约束的表。我正在将数据插入一个表中,我希望我不必像上面那样查找每个字段的默认值并将其写入insert查询。我有大约50张桌子要做这个。但是我越是思考这个问题,我就越觉得我想在这里做的事情是不可能的。这没关系,但没有必要。原始函数使用
regclass
参数,因此可以传递模式限定的表名,例如
select copy_table_with_defaults('public.table_with_nulls'::regclass,'public.table_with_defaults'::regclass)谢谢。我以前从未使用过regclass参数。