3

私は数時間、添字の基になる配列の基準に基づいて配列の添字をフィルター処理し、それらの添字の配列を作成する関数を作成しようと試みましたが、無駄でした。

私が扱っているデータ構造は、次のサンプルに似ています (比較する列が多く、ルールが複雑で、データ型が混在していることを除いて)。

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 の親に最も近い次の非 null 値を取得し、現在のレコードからの階層距離に基づいてそれらを比較するクエリを実行する必要があります。したがって、たとえば、abbreviation1 と abbreviation2 の最初の非 null 値が両方とも同じレコード レベルにある場合、abbreviation1 が優先されます。一方、最初の null 以外の abbreviation2 が現在のレコードに近い場合は、abbreviation1 の対応する null 以外の値よりも近い場合、abbreviation2 が使用されます。

したがって、上記のサンプル テーブルで説明したクエリは次のようになります。

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,3,1}べきときに返されます{5,4,2,1}

select filter_array_subscripts(array['This',NULL,'is',NULL,'insane!']::text[]
                               ,'is',1,True);

これが機能しない理由がforeachわかりません。配列反復構文を使用してみましたが、反復値を に含まれるスカラー型にキャストする方法がわかりませんanyarray

これを修正するにはどうすればよいですか?

4

1 に答える 1

4

PostgreSQL 8.4 以降で利用可能なRECURSIVE CTEを使用すると、この作業全体を大幅に簡素化できます。

テスト テーブル (誰もがこのような形式でテスト データを簡単に提供できるようにします):

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

これは、すべてのパスに null 以外の値があること、またはそのような行が結果から削除されることを前提としています。

于 2012-06-18T03:33:19.590 に答える