Bien optimisé :
WITH t(a, b, ct) AS (
SELECT columna, columnb, count(*)::int
FROM test_1
GROUP BY 1, 2
)
, matrix AS (
SELECT a.*, b.*, COALESCE(t.ct, 0) AS ct
FROM (SELECT DISTINCT ON (a) a, right(a, -1)::int AS sorta FROM t) a
CROSS JOIN (SELECT DISTINCT ON (b) b, right(b, -1)::int AS sortb FROM t) b
LEFT JOIN t USING (a, b)
)
(
SELECT a AS ab, array_agg('"' || b || '" = ' || ct ORDER BY sortb) AS x
FROM matrix
GROUP BY 1, sorta
ORDER BY sorta
)
UNION ALL
(
SELECT b , array_agg('"' || a || '" = ' || ct ORDER BY sorta)
FROM matrix
GROUP BY 1, sortb
ORDER BY sortb
);
Toutes les parenthèses sont obligatoires.