Sie können dies mit crosstab()
tun aus dem Zusatzmodul 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);
Wenn NULL
statt 0
funktioniert auch, es kann einfach SELECT *
sein in der äußeren Abfrage.
Detaillierte Erklärung:
- PostgreSQL-Kreuztabellenabfrage
Die besondere "Schwierigkeit" hier:kein eigentlicher "Wert". Fügen Sie also 1 AS val
hinzu als letzte Spalte.
Unbekannte Anzahl an Kategorien
Eine vollständig dynamische Abfrage (mit unbekanntem Ergebnistyp) ist in einer einzelnen Abfrage nicht möglich. Du brauchst zwei Abfragen. Erstellen Sie zunächst dynamisch eine Anweisung wie die obige und führen Sie sie dann aus. Einzelheiten:
-
Auswählen mehrerer max()-Werte mit einer einzigen SQL-Anweisung
-
PostgreSQL Spalten in Zeilen konvertieren? Transponieren?
-
Generieren Sie dynamisch Spalten für Kreuztabellen in PostgreSQL
-
Dynamische Alternative zum Pivot mit CASE und GROUP BY
Zu viele Kategorien
Wenn Sie die maximale Spaltenanzahl (1600) überschreiten, ist eine klassische Kreuztabelle nicht möglich, da das Ergebnis nicht mit einzelnen Spalten dargestellt werden kann. (Außerdem wäre das menschliche Auge kaum in der Lage, eine Tabelle mit so vielen Spalten zu lesen)
Arrays oder Dokumenttypen wie hstore
oder jsonb
sind die Alternative. Hier ist eine Lösung mit Arrays:
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;
-
Erstellen Sie das vollständige Werteraster mit:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
-
LEFT JOIN
vorhandene Kombinationen, sortieren Sie sie nach dem numerischen Teil des Namens und aggregieren Sie sie in Arrays.right(colb, -1)::int
schneidet das führende Zeichen von 'A3' ab und wandelt die Ziffern in Ganzzahlen um, damit wir eine korrekte Sortierreihenfolge erhalten.
Basismatrix
Wenn Sie nur eine Tabelle von 0
wollen eine 1
wobei x = y
, das ist günstiger zu haben:
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-Geige aufbauend auf dem, das Sie in den Kommentaren angegeben haben.
Beachten Sie, dass sqlfiddle.com derzeit einen Fehler hat, der die Anzeige von Array-Werten beendet. Also wandle ich in text
um da, um es zu umgehen.