_array_agg
_を使用して名前を収集する場合、コンマで区切られた名前を取得しますが、null
値がある場合、そのnullも集計の名前として使用されます。例えば :
_SELECT g.id,
array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users,
array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users
FROM groups g
GROUP BY g.id;
_
_,Larry,Phil
_の代わりに_Larry,Phil
_を返します(私の9.1.2では、_NULL,Larry,Phil
_と表示されます)。 this fiddleのように
代わりに、string_agg()
を使用すると、 here のような名前のみ(空のコンマまたはヌルなし)が表示されます。
問題は、サーバーに_Postgres 8.4
_がインストールされており、string_agg()
がそこで動作しないことです。 array_aggをstring_agg()と同様に動作させる方法はありますか?
select
id,
(select array_agg(a) from unnest(canonical_users) a where a is not null) canonical_users,
(select array_agg(a) from unnest(non_canonical_users) a where a is not null) non_canonical_users
from (
SELECT g.id,
array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users,
array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users
FROM groups g
GROUP BY g.id
) s
または、nullを排除するarray_to_string
を使用して、より単純で安価になる場合があります。
SELECT
g.id,
array_to_string(
array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END)
, ','
) canonical_users,
array_to_string(
array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END)
, ','
) non_canonical_users
FROM groups g
GROUP BY g.id
Postgresql-9.3では、これを行うことができます。
SELECT g.id,
array_remove(array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END), NULL) canonical_users,
array_remove(array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END), NULL) non_canonical_users
FROM groups g
GROUP BY g.id;
更新:postgresql-9.4で;
SELECT g.id,
array_agg(g.users) FILTER (WHERE g.canonical = 'Y') canonical_users,
array_agg(g.users) FILTER (WHERE g.canonical = 'N') non_canonical_users
FROM groups g
GROUP BY g.id;
配列集合体からNULLを削除するという一般的な問題を解決する際、問題を攻撃する主な方法は2つあります。array_agg(unnest(array_agg(x))を実行するか、カスタム集合体を作成するかです。
最初の形式は 上記 :
SELECT
array_agg(u)
FROM (
SELECT
unnest(
array_agg(v)
) as u
FROM
x
) un
WHERE
u IS NOT NULL;
二番目:
/*
With reference to
http://ejrh.wordpress.com/2011/09/27/denormalisation-aggregate-function-for-postgresql/
*/
CREATE OR REPLACE FUNCTION fn_array_agg_notnull (
a anyarray
, b anyelement
) RETURNS ANYARRAY
AS $$
BEGIN
IF b IS NOT NULL THEN
a := array_append(a, b);
END IF;
RETURN a;
END;
$$ IMMUTABLE LANGUAGE 'plpgsql';
CREATE AGGREGATE array_agg_notnull(ANYELEMENT) (
SFUNC = fn_array_agg_notnull,
STYPE = ANYARRAY,
INITCOND = '{}'
);
2番目の呼び出しは(当然)最初の呼び出しよりも少し見た目が良いです:
xからarray_agg_notnull(v)を選択します。
このスレッドはかなり古いものですが、これを追加していますが、小さな配列で非常にうまく機能するこの巧妙なトリックに出くわしました。追加のライブラリや関数なしでPostgres 8.4以降で実行されます。
_string_to_array(array_to_string(array_agg(my_column)))::int[]
_
array_to_string()
メソッドは実際にnullを取り除きます。
コメントで提案されているように、配列内のヌルを置換する関数を作成できますが、コメントでリンクされているスレッドでも指摘されているように、この種の集計関数を作成する必要がある場合、集計関数の効率を損ないます、分割してから再度集約します。
配列にnullを保持することは、Array_Aggの単なる(おそらく望ましくない)機能だと思います。これを回避するには、サブクエリを使用できます。
SELECT COALESCE(y.ID, n.ID) ID,
y.Users,
n.Users
FROM ( SELECT g.ID, ARRAY_AGG(g.Users) AS Users
FROM Groups g
WHERE g.Canonical = 'Y'
GROUP BY g.ID
) y
FULL JOIN
( SELECT g.ID, ARRAY_AGG(g.Users) AS Users
FROM Groups g
WHERE g.Canonical = 'N'
GROUP BY g.ID
) n
ON n.ID = y.ID