可能であれば、このデータをバイトマップにビットマップとして保存したいと思います。一連のバイト値を取得してバイトに変換する方法は次のとおりです。
WITH bytes(b) AS (SELECT x % 256 FROM generate_series(1,53000) x)
SELECT ('\x'||string_agg(lpad(to_hex(b),2,'0'),''))::bytea FROM bytes;
関数を使用して、バイト配列のフィールドまたは範囲にアクセスできますsubstr
。この bytea は、線形のピクセル配列として構成されていますが、従来のビットマップ形式に構成する方が便利な場合があります。また、ピクセルが 1 バイトを超える場合は、ビッグ エンディアンとリトルエンディアンに対処する必要がある場合があります。これは SQL で行うこともできますが、PL/Perl のような手続き型言語の方がはるかに簡単です。
そうでない場合は、多次元配列がやや合理的な選択になります。
generate_series
便利なテストのためにフィールドの代わりにステートメントを使用するpix_val
と、このクエリは 2 つの集計パスを使用して整数の 2 次元配列を生成します。
SELECT ('{'||string_agg(subarray, ',')||'}')::integer[] AS arr
FROM (
SELECT array_agg(x order by x)::text
FROM generate_series(1,53000) x
GROUP BY width_bucket(x, 1, 53001, 100)
) a(subarray);
array_agg
2 次元配列の文字列リテラル形式の不幸な使用は、配列を集約できないという事実によって必要になります。私の見解では、これは PostgreSQL の本当の問題です。一般に、その多次元配列は扱いにくく、ほとんどのアプリケーションや言語が配列を実装する方法と矛盾しています。
配列にインデックスを付けることで、配列からフィールドを取得できます。例:
regress=> SELECT ('{'||string_agg(subarray, ',')||'}')::integer[] AS arr INTO test FROM (SELECT array_agg(x order by x)::text from generate_series(1,53000) x GROUP BY width_bucket(x, 1, 53001, 100)) a(subarray);
regress=> \d test
Table "public.test"
Column | Type | Modifiers
--------+-----------+-----------
arr | integer[] |
test
2 次元の 1 つの配列が含まれます。
regress=> \x
regress=> select array_dims(test.arr), array_ndims(test.arr), array_length(test.arr,1), array_length(test.arr,2) FROM test;
-[ RECORD 1 ]+---------------
array_dims | [1:100][1:530]
array_ndims | 2
array_length | 100
array_length | 530
2 レベルのインデックスで要素を取得できます。
regress=> SELECT test.arr[4][4] FROM test;
arr
------
1594
(1 row)
またはスライスした「列」:
regress=> SELECT test.arr[4:4][1:530] FROM test;
奇妙なことに、これはまだ 2 次元配列であり、最上位の次元は 1 要素の深さです。unnest
必要に応じてandを使用して (非効率的に) フラット化できarray_agg
ます。
ご覧のとおり、PostgreSQL の 2 次元配列はやや奇妙ですが、あなたがやろうとしていることも同様です。