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

标签 arrays postgresql hierarchy plpgsql postgresql-9.1

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

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

id hierarchy abbreviation1 abbreviation2
1  {1}       SB            GL
2  {2,1}     NULL          NULL
3  {3,2,1}   NULL          TC
4  {4,2,1}   NULL          NULL

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

因此上述示例表上的描述查询将产生;

id abbreviation
1  SB
2  SB
3  TC
4  SB

为了完成这个任务,我需要生成一个过滤后的数组下标数组(在缩写列上执行 array_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 数组迭代语法,但我不知道如何将迭代值转换为 中包含的标量类型任意数组

如何解决这个问题?

最佳答案

您可以通过使用 RECURSIVE CTE 在很大程度上简化整个工作。 ,在 PostgreSQL 8.4 或更高版本中可用:

测试表(方便大家以this这样的形式提供测试数据):

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

返回:

id | abbr
---+-----
1  | SB
2  | SB
3  | TC
4  | SB

这假定每个路径上都有一个非空值,否则这些行将从结果中删除。

关于arrays - 在分层表中沿路径(节点数组)查找第一个非空值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11011047/

相关文章:

postgresql - 创建 Wildfly 10 数据源时出现问题

python - 仅显示所选对象的层次结构

mysql - 如何删除邻接列表模型中的父级及其子级?

arrays - 对ArrayController的内容进行排序

php - Ajax 自动建议不会按顺序显示字母。

javascript - 在 React Native 中使用 Map 与 Flatlist

java - 有什么方法可以从层次结构中更高的类中退出命名循环(或其他方式)?

java - 构造函数在java中使用多个数组

postgresql - 如果 RedShift 中的字段类型是整数,我如何输入 varchar 值?

postgresql - pip 安装失败,/usr/bin/clang : No such file or directory