Możesz to zrobić za pomocą crosstab() z dodatkowego modułu 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);
Jeśli NULL zamiast 0 działa też, może to być po prostu SELECT * w zewnętrznym zapytaniu.
Szczegółowe wyjaśnienie:
- Kwerendy PostgreSQL Crosstab
Szczególna „trudność” tutaj:brak rzeczywistej „wartości”. Dodaj więc 1 AS val jako ostatnia kolumna.
Nieznana liczba kategorii
Całkowicie dynamiczne zapytanie (z nieznanym typem wyniku) nie jest możliwe w pojedynczym zapytaniu. Potrzebujesz dwóch zapytania. Najpierw zbuduj dynamicznie instrukcję taką jak powyżej, a następnie ją wykonaj. Szczegóły:
-
Wybór wielu wartości max() za pomocą jednej instrukcji SQL
-
PostgreSQL konwertuje kolumny na wiersze? Transponować?
-
Dynamicznie generuj kolumny dla tabeli krzyżowej w PostgreSQL
-
Dynamiczna alternatywa dla pivota z CASE i GROUP BY
Zbyt wiele kategorii
Jeśli przekroczysz maksymalną liczbę kolumn (1600), klasyczna tabela przestawna jest niemożliwa, ponieważ wynik nie może być reprezentowany przez pojedyncze kolumny. (Ponadto ludzkie oczy prawie nie byłyby w stanie odczytać tabeli z tyloma kolumnami)
Tablice lub typy dokumentów, takie jak hstore lub jsonb są alternatywą. Oto rozwiązanie z tablicami:
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;
-
Zbuduj pełną siatkę wartości za pomocą:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a -
LEFT JOINistniejące kombinacje, uporządkuj według numerycznej części nazwy i agreguj w tablice.right(colb, -1)::intprzycina wiodący znak z „A3” i przekształca cyfry na liczby całkowite, dzięki czemu uzyskujemy właściwą kolejność sortowania.
Macierz podstawowa
Jeśli chcesz tylko tabelę 0 1 gdzie x = y , można to zrobić taniej:
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;
Skrzypce SQL oparty na tym, który podałeś w komentarzach.
Zauważ, że sqlfiddle.com ma obecnie błąd, który zabija wyświetlanie wartości tablicy. Więc przesyłam do text tam, aby to obejść.