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 JOIN
istniejące kombinacje, uporządkuj według numerycznej części nazwy i agreguj w tablice.right(colb, -1)::int
przycina 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ść.