Select 列如果存在否则为空 - PSQL

Select column if exists else null - PSQL

以下函数动态连接不同的表。

create or replace function unified_tables() returns table(  
                      1         TEXT
                    , 2         TEXT
                    , 3         TEXT
                    , 4         TEXT
                    , 5         JSONB
                    , 6         BIGINT
                    , 7         BIGINT
                    , 8         TEXT
                    , 9         TEXT
                    , 10        TIMESTAMPTZ
                    )
as
$$
declare
  a record;
begin
  for a in select table_schema
                    from information_schema.tables
                    where table_name = 'name' 
  loop
     return query 
        execute format('select  %L as source_schema,  *  from %I.name', a.table_schema,  a.table_schema);
  end loop;
end;
$$
language plpgsql;

不幸的是,并非所有调用的表都具有 RETURNS TABLE 中指定的所有列。

准确地说,有 15 个表(循环超过 200 个表)缺少第 2 列,两个表缺少第 4 列,五个表缺少第 9 列。

进入循环的未来表也可能会丢失列。我无法控制源结构。

如何继续使用为缺失列添加空值的函数,以维护 RETURNS TABLE 中定义的结构?

您将无法编写能够满足您需求的查询。您将需要构建代码。最简单的方法是将目标 table 的 information_schema.columns 与所需列名列表一起使用。这本身就产生了一个问题,因为“未来 tables 进入循环也可能会丢失列”,并且您可能事先不知道这些列是什么,以及必要列更改时的维护问题。现在这并不意味着没有简单的答案。只是不是您要查询的内容。
最简单的方法是使用所需的列名和数据类型创建一个模板 table。然后是一个将模板列与目标 table 列连接起来的函数。对于列维护,您只需更改模板 table。 (参见 Demo here

create table unified_def
             (c1    text
             ,c2    text
             ,c3    text
             ,c4    text
             ,c5    jsonb
             ,c6    bigint
             ,c7    bigint
             ,c8    text
             ,c9    text
             ,c10   timestamptz
             );   

create or replace 
function unified_tables(target_table_in text) 
 returns setof unified_def
 language plpgsql 
as $$
declare
   def_cur cursor( c_tgt_table text ) for  
          with ud(column_name,data_type, ordinal_position) as 
               ( select column_name,data_type,ordinal_position  
                   from information_schema.columns 
                  where table_name = 'unified_def' 
                   order by ordinal_position         
               )  --select * from ud
             , tgt (column_name) as 
               ( select column_name 
                   from information_schema.columns        
                  where table_name = c_tgt_table 
               ) --select * from tgt
          select ud.column_name cname
               , tgt.column_name tname
               , ud.data_type
            from ud left join tgt on (ud.column_name = tgt.column_name);

   l_from     text = ' from <tbl>';
   l_sep      text = '';
   l_stmt     text = 'select '; 
begin
     for cdef in def_cur(target_table_in) 
     loop 
         l_stmt =  l_stmt || l_sep 
               ||  coalesce(cdef.tname, 'null::' || cdef.data_type); 
         l_sep  = ',';
     end loop; 
     
     l_stmt = l_stmt || replace (l_from, '<tbl>', target_table_in);
    
     raise notice E'Run Statement \n%', l_stmt; 
     return query execute l_stmt;
end;
$$; 

注意: 上述函数假定模板和目标 table 之间的数据类型兼容。如果存在这种情况不成立的情况,则需要额外的代码来处理这种情况。在任何情况下,最终的 return 类型 必须 符合模板的定义 table.