Arrays 沿分层表中的路径(节点数组)查找第一个非空值

Arrays 沿分层表中的路径(节点数组)查找第一个非空值,arrays,postgresql,hierarchy,plpgsql,postgresql-9.1,Arrays,Postgresql,Hierarchy,Plpgsql,Postgresql 9.1,几个小时以来,我一直在徒劳地尝试创建一个函数,该函数根据下标所在数组的条件过滤数组下标,然后创建这些下标的数组 我正在处理的数据结构与下面的示例类似(除了要比较的列更多,规则更复杂,数据类型混合): 我需要运行一个查询,为abbreviation1和abbreviation2获取最接近父级的下一个非空值,并根据与当前记录的层次距离对它们进行比较,以便为缩写获取单个值。因此,例如,如果abbreviation1和abbreviation2的第一个非空值都位于同一记录级别,则abbreviation

几个小时以来,我一直在徒劳地尝试创建一个函数,该函数根据下标所在数组的条件过滤数组下标,然后创建这些下标的数组

我正在处理的数据结构与下面的示例类似(除了要比较的列更多,规则更复杂,数据类型混合):

我需要运行一个查询,为abbreviation1和abbreviation2获取最接近父级的下一个非空值,并根据与当前记录的层次距离对它们进行比较,以便为缩写获取单个值。因此,例如,如果abbreviation1和abbreviation2的第一个非空值都位于同一记录级别,则abbreviation1将优先;另一方面,如果第一个非空的abbreviation2更接近当前记录,则将使用abbreviation1对应的非空值,然后使用abbreviation2

因此,上述示例表上的查询将产生:

id abbreviation
1  SB
2  SB
3  TC
4  SB
为了完成这项任务,我需要生成一个经过过滤的数组下标数组(在对缩写列执行
array\u agg()
之后),其中只包含缩写列中的值不为null的下标

基于我疲惫的头脑中的所有逻辑,下面的函数应该可以工作,但不能

CREATE OR REPLACE FUNCTION filter_array_subscripts(rawarray anyarray,criteria anynonarray,dimension integer, reverse boolean DEFAULT False) 
  RETURNS integer[] as 
$$
DECLARE
  outarray integer[] := ARRAY[]::integer[];
  x integer;
  BEGIN
    for i in array_lower(rawarray,dimension)..array_upper(rawarray,dimension) LOOP
      IF NOT criteria IS NULL THEN
        IF NOT rawarray[i] IS NULL THEN
          IF NOT rawarray[i] = criteria THEN
            IF reverse = False THEN
              outarray := array_append(outarray,i);
            ELSE
              outarray := array_prepend(i,outarray);
            END IF;
         ELSE
            IF reverse = False THEN
              outarray := array_append(outarray,i);
            ELSE
              outarray := array_prepend(i,outarray);
            END IF;
         END IF;
        END IF;
      ELSE
        IF NOT rawarray[i] is NULL THEN
          IF reverse = False THEN
            outarray := array_append(outarray,i);
          ELSE
            outarray := array_prepend(i,outarray);
          END IF;
        END IF;
      END IF;
    END LOOP;
    RETURN outarray;
  END; 
$$ LANGUAGE plpgsql;
例如,下面的查询在应该返回
{5,4,2,1}
时返回
{5,3,1}

select filter_array_subscripts(array['This',NULL,'is',NULL,'insane!']::text[]
                               ,'is',1,True);
我不知道为什么这不起作用,我尝试过使用
foreach
数组迭代语法,但我不知道如何将迭代值强制转换为
anyarray
中包含的标量类型


如何解决此问题?

您可以使用PostgreSQL 8.4或更高版本中提供的:

测试表(使每个人都能更容易地以这样的形式提供测试数据):

查询:

WITH RECURSIVE x AS (
    SELECT id
         , COALESCE(abbreviation1, abbreviation2) AS abbr
         , hierarchy[2] AS parent_id
    FROM   tbl

    UNION ALL
    SELECT x.id
         , COALESCE(parent.abbreviation1, parent.abbreviation2) AS abbr
         , parent.hierarchy[2] AS parent_id
    FROM   x
    JOIN   tbl AS parent ON parent.id = x.parent_id
    WHERE  x.abbr IS NULL  -- stop at non-NULL value
    )
SELECT id, abbr
FROM   x
WHERE  abbr IS NOT NULL  -- discard intermediary NULLs
ORDER  BY id
返回:

id |缩写
---+-----
1 |某人
2 |某人
3 | TC
4 |某人
这假定每个路径上都有一个非null值,否则这些行将从结果中删除

CREATE TEMP TABLE tbl (
    id int
  , hierarchy int[]
  , abbreviation1 text
  , abbreviation2 text
);

INSERT INTO tbl VALUES
 (1, '{1}',     'SB', 'GL')
,(2, '{2,1}',   NULL, NULL)
,(3, '{3,2,1}', NULL, 'TC')
,(4, '{4,2,1}', NULL, NULL);
WITH RECURSIVE x AS (
    SELECT id
         , COALESCE(abbreviation1, abbreviation2) AS abbr
         , hierarchy[2] AS parent_id
    FROM   tbl

    UNION ALL
    SELECT x.id
         , COALESCE(parent.abbreviation1, parent.abbreviation2) AS abbr
         , parent.hierarchy[2] AS parent_id
    FROM   x
    JOIN   tbl AS parent ON parent.id = x.parent_id
    WHERE  x.abbr IS NULL  -- stop at non-NULL value
    )
SELECT id, abbr
FROM   x
WHERE  abbr IS NOT NULL  -- discard intermediary NULLs
ORDER  BY id