Можете да направите това с crosstab()
от допълнителния модул tablefunc:
SELECT b
, COALESCE(a1, 0) AS "A1"
, COALESCE(a2, 0) AS "A2"
, COALESCE(a3, 0) AS "A3"
, ... -- all the way up to "A30"
FROM crosstab(
'SELECT colb, cola, 1 AS val FROM matrix
ORDER BY 1,2'
, $$SELECT 'A'::text || g FROM generate_series(1,30) g$$
) AS t (b text
, a1 int, a2 int, a3 int, a4 int, a5 int, a6 int
, a7 int, a8 int, a9 int, a10 int, a11 int, a12 int
, a13 int, a14 int, a15 int, a16 int, a17 int, a18 int
, a19 int, a20 int, a21 int, a22 int, a23 int, a24 int
, a25 int, a26 int, a27 int, a28 int, a29 int, a30 int);
Ако NULL
вместо 0
работи също, може да бъде просто SELECT *
във външната заявка.
Подробно обяснение:
- PostgreSQL Crosstab Query
Специалната "трудност" тук:няма действителна "стойност". Така че добавете 1 AS val
като последна колона.
Неизвестен брой категории
Напълно динамична заявка (с неизвестен тип резултат) не е възможна в една заявка. Нуждаете се от два запитвания. Първо изградете динамично изявление като горното, след което го изпълнете. Подробности:
-
Избиране на множество max() стойности с помощта на един SQL израз
-
PostgreSQL конвертира колони в редове? Транспониране?
-
Динамично генериране на колони за кръстосана таблица в PostgreSQL
-
Динамична алтернатива на завъртане с CASE и GROUP BY
Твърде много категории
Ако надвишите максималния брой колони (1600), класическата кръстосана таблица е невъзможна, тъй като резултатът не може да бъде представен с отделни колони. (Освен това човешките очи едва ли биха могли да разчетат таблица с толкова много колони)
Масиви или типове документи като hstore
или jsonb
са алтернативата. Ето решение с масиви:
SELECT colb, array_agg(cola) AS colas
FROM (
SELECT colb, right(colb, -1)::int AS sortb
, CASE WHEN m.cola IS NULL THEN 0 ELSE 1 END AS cola
FROM (SELECT DISTINCT colb FROM matrix) b
CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
LEFT JOIN matrix m USING (colb, cola)
ORDER BY sortb, right(cola, -1)::int
) sub
GROUP BY 1, sortb
ORDER BY sortb;
-
Изградете пълната мрежа от стойности с:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
-
LEFT JOIN
съществуващи комбинации, подредете по числовата част на името и обединете в масиви.right(colb, -1)::int
отрязва главния символ от „A3“ и прехвърля цифрите към цяло число, така че да получим правилен ред на сортиране.
Основна матрица
Ако просто искате таблица с 0
1
където x = y
, това може да бъде по-евтино:
SELECT x, array_agg((x = y)::int) AS y_arr
FROM generate_series(1,10) x
, generate_series(1,10) y
GROUP BY 1
ORDER BY 1;
SQL Fiddle надграждане на този, който сте предоставили в коментарите.
Имайте предвид, че sqlfiddle.com в момента има грешка, която убива показването на стойности на масива. Затова прехвърлям към text
там, за да го заобиколите.