如何使用合并或变体来提取超过1个值?

时间:2015-05-20 20:07:13

标签: sql postgresql coalesce notnull

这是关于PostgreSQL中COALESCE的问题。在我当前使用的视图中 COALESCE获取列表中的第一个NOT NULL值:

COALESCE(vw_header_to_node_13.subsetname,
vw_header_to_node_12.subsetname, 
vw_header_to_node_11.subsetname,
vw_header_to_node_10.subsetname,
vw_header_to_node_9.subsetname,
vw_header_to_node_8.subsetname,
vw_header_to_node_7.subsetname,
vw_header_to_node_6.subsetname,
vw_header_to_node_5.subsetname,
vw_header_to_node_4.subsetname,
vw_header_to_node_3.subsetname,
vw_header_to_node_2.subsetname,
vw_header_to_node_1.subsetname,
vw_header_to_node.subsetname,
vw_header_to_node.setname)
AS prctr1

我刚收到通知,我现在需要在第一个NOT NULL字段后抓取第一个NOT NULL字段和后面的2个字段,而不是只获取第一个NOT NULL字段。例如,如果vw_header_to_node_8.subsetname是第一个NOT NULL字段,我想抓住vw_header_to_node_8.subsetnamevw_header_to_node_7.subsetname,& vw_header_to_node_6.subsetname。我知道这不是COALESCE正常运作的方式,但有没有人知道有任何变化或方法可以实现这一目标?

1 个答案:

答案 0 :(得分:3)

如果应从列表中排除所有空值,则此方法应该起作用:

  1. 将列表转换为数组,
  2. 从数组中删除空值
  3. 选择数组的三个第一个元素。
  4. 示例:

    with test as (
        select 
            null::text     as v1,
            'apple'::text  as v2,
            null::text     as v3,
            'banana'::text as v4,
            'pear'::text   as v5)
    
    select a[1] val1, a[2] val2, a[3] val3
    from (      
        select 
            array_remove(
                array[v1, v2, v3, v4, v5], null) a
        from test
        ) alias
    
     val1  |  val2  | val3
    -------+--------+------
     apple | banana | pear
    

    如果第二个和第三个值可以为null,我们应该在步骤2中修剪数组中的第一个空值。 Postgres中没有适当的功能,但您可以自己编写。

    create function array_ltrim_nulls(arr anyarray)
    returns anyarray language plpgsql immutable
    as $$
    declare 
        i integer;
        l integer = array_length(arr, 1);
    begin
        for i in 1..l loop
            if arr[i] is not null then
                return arr[i:l];
            end if;
        end loop;
        return null;
    end $$;
    
    with test as (
        select 
            null::text     as v1,
            'apple'::text  as v2,
            null::text     as v3,
            'banana'::text as v4,
            'pear'::text   as v5)
    
    select a[1] val1, a[2] val2, a[3] val3
    from (      
        select 
            array_ltrim_nulls(
                array[v1, v2, v3, v4, v5]) a
        from test
        ) alias
    
     val1  | val2 |  val3
    -------+------+--------
     apple |      | banana      
    

    为了便于使用,我已将以下功能添加到我的标准功能集中。也许这个功能对你最有用。函数参数的数量是可变的。您只需要确保所有参数都是相同的类型。

    create function array_coalesce (variadic arr anyarray)
    returns anyarray language sql immutable
    as $$
        select array_remove(arr, null);
    $$;
    
    select array_coalesce(null::text, 'apple', null, 'banana', 'pear') arr;
             arr         
    ---------------------
     {apple,banana,pear}
    
    select array_coalesce(null::int, 1, null, 2, 3, 4, null, 5) arr;
         arr     
    -------------
     {1,2,3,4,5}
    
    select (array_coalesce(null::int, 1, null, 2, 3, 4, null, 5))[1:3] arr;
         arr     
    -------------
     {1,2,3}