SELECT C.id, C.name, json_agg(E) AS emails FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id;
Postgres 9.3は例えば出力を作成します
id | name | emails
-----------------------------------------------------------
1 | Ryan | [{"id":3,"user_id":1,"email":"[email protected]"},{"id":4,"user_id":1,"email":"[email protected]"}]
2 | Nick | [null]
LEFT JOINを使用しているため、右テーブルの一致がない場合があります。そのため、右テーブルの列は空の(null)値に置き換えられます。その結果、[null]
JSON集約の1つとして。
null
を無視/削除して、空のJSON配列[]
右テーブルの列がnullの場合
乾杯!
9.4では、合体および集約フィルター式を使用できます。
SELECT C.id, C.name,
COALESCE(json_agg(E) FILTER (WHERE E.user_id IS NOT NULL), '[]') AS emails
FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id, C.name
ORDER BY C.id;
フィルター式は、左結合条件が満たされていないため、集計がNULLの行を処理できないようにします。そのため、json [null]の代わりにデータベースnullになります。データベースがヌルになったら、通常どおり合体を使用できます。
http://www.postgresql.org/docs/9.4/static/sql-expressions.html#SYNTAX-AGGREGATES
このようなものでしょうか?
select
c.id, c.name,
case when count(e) = 0 then '[]' else json_agg(e) end as emails
from contacts as c
left outer join emails as e on c.id = e.user_id
group by c.id
参加する前にグループ化することもできます(このバージョンの方がいいと思います。もう少しわかりやすいです):
select
c.id, c.name,
coalesce(e.emails, '[]') as emails
from contacts as c
left outer join (
select e.user_id, json_agg(e) as emails from emails as e group by e.user_id
) as e on e.user_id = c.id
これが実際にPostgreSQLのバグである場合、9.4で修正されることを望みます。とてもうるさい。
SELECT C.id, C.name,
COALESCE(NULLIF(json_agg(E)::TEXT, '[null]'), '[]')::JSON AS emails
FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id;
私は個人的にCOALESCEビットを実行せず、単にNULLを返します。あなたの電話。
この回答 (申し訳ありませんが、ユーザー名にリンクできないようです)を使用しましたが、少し改善したと思います。
配列バージョンの場合、次のことができます
array_to_json(array_agg())
呼び出しの代わりに json_agg を使用しますこれを取得します:
CREATE OR REPLACE FUNCTION public.json_clean_array(p_data JSON)
RETURNS JSON
LANGUAGE SQL IMMUTABLE
AS $$
-- removes elements that are json null (not sql-null) or empty
SELECT json_agg(value)
FROM json_array_elements(p_data)
WHERE value::text <> 'null' AND value::text <> '""';
$$;
9.3のオブジェクトバージョンでは、次のことができます。
WITH
句を取り除きますこれを取得します:
CREATE OR REPLACE FUNCTION public.json_clean(p_data JSON)
RETURNS JSON
LANGUAGE SQL IMMUTABLE
AS $$
-- removes elements that are json null (not sql-null) or empty
SELECT ('{' || string_agg(to_json(key) || ':' || value, ',') || '}') :: JSON
FROM json_each(p_data)
WHERE value::TEXT <> 'null' AND value::TEXT <> '""';
$$;
9.4では、新しく追加された json_object_agg を使用できるため、オブジェクトを構築するために文字列Assemblyを使用する必要はありません。
CREATE OR REPLACE FUNCTION public.json_clean(p_data JSON)
RETURNS JSON
LANGUAGE SQL IMMUTABLE
AS $$
-- removes elements that are json null (not sql-null) or empty
SELECT json_object_agg(key, value)
FROM json_each(p_data)
WHERE value::TEXT <> 'null' AND value::TEXT <> '""';
$$;
JSON配列をフィルタリングするための独自の関数を作成しました。
CREATE OR REPLACE FUNCTION public.json_clean_array(data JSON)
RETURNS JSON
LANGUAGE SQL
AS $$
SELECT
array_to_json(array_agg(value)) :: JSON
FROM (
SELECT
value
FROM json_array_elements(data)
WHERE cast(value AS TEXT) != 'null' AND cast(value AS TEXT) != ''
) t;
$$;
私はそれを
select
friend_id as friend,
json_clean_array(array_to_json(array_agg(comment))) as comments
from some_entity_that_might_have_comments
group by friend_id;
もちろん、postgresql 9.3でのみ機能します。オブジェクトフィールドにも同様のものがあります:
CREATE OR REPLACE FUNCTION public.json_clean(data JSON)
RETURNS JSON
LANGUAGE SQL
AS $$
SELECT
('{' || string_agg(to_json(key) || ':' || value, ',') || '}') :: JSON
FROM (
WITH to_clean AS (
SELECT
*
FROM json_each(data)
)
SELECT
*
FROM json_each(data)
WHERE cast(value AS TEXT) != 'null' AND cast(value AS TEXT) != ''
) t;
$$;
編集:ここで私のGistでいくつかのユーティリティを見ることができます(元々は私のものではありませんが、他のstackoverflowソリューションから取ったものです) https://Gist.github.com/le-doude/8b0e89d71a32efd2128 =
おそらく、Roman Pekarのソリューションよりもパフォーマンスは劣りますが、少しすっきりしています。
select
c.id, c.name,
array_to_json(array(select email from emails e where e.user_id=c.id))
from contacts c
この方法は機能しますが、より良い方法があります:(
SELECT C.id, C.name,
case when exists (select true from emails where user_id=C.id) then json_agg(E) else '[]' end
FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id, C.name;
少し異なりますが、他の人には役立つかもしれません:
配列内のすべてのオブジェクトが同じ構造である場合(たとえば、jsonb_build_object
を使用して作成するため)、array_remove
で使用する「同じ構造のNULLオブジェクト」を定義できます。
...
array_remove(
array_agg(jsonb_build_object('att1', column1, 'att2', column2)),
to_jsonb('{"att1":null, "att2":null}'::json)
)
...