Anda dapat melakukannya dengan crosstab()
dari tablefunc modul tambahan:
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);
Jika NULL
bukannya 0
berfungsi juga, bisa saja SELECT *
di kueri luar.
Penjelasan detail:
- Kueri Tab Silang PostgreSQL
"Kesulitan" khusus di sini:tidak ada "nilai" yang sebenarnya. Jadi tambahkan 1 AS val
sebagai kolom terakhir.
Jumlah kategori tidak diketahui
Kueri yang sepenuhnya dinamis (dengan jenis hasil yang tidak diketahui) tidak dimungkinkan dalam satu kueri. Anda membutuhkan dua pertanyaan. Pertama buat pernyataan seperti di atas secara dinamis, lalu jalankan. Detail:
-
Memilih beberapa nilai max() menggunakan satu pernyataan SQL
-
PostgreSQL mengonversi kolom menjadi baris? Transpos?
-
Buat kolom secara dinamis untuk tab silang di PostgreSQL
-
Alternatif dinamis untuk pivot dengan CASE dan GROUP BY
Terlalu banyak kategori
Jika Anda melebihi jumlah maksimum kolom (1600), tab silang klasik tidak mungkin dilakukan, karena hasilnya tidak dapat direpresentasikan dengan kolom individual. (Juga, mata manusia tidak akan bisa membaca tabel dengan kolom sebanyak itu)
Array atau jenis dokumen seperti hstore
atau jsonb
adalah alternatifnya. Berikut adalah solusi dengan array:
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;
-
Bangun kisi nilai lengkap dengan:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
-
LEFT JOIN
kombinasi yang ada, urutkan berdasarkan bagian numerik dari nama dan gabungkan ke dalam array.right(colb, -1)::int
memangkas karakter utama dari 'A3' dan memasukkan angka ke bilangan bulat sehingga kami mendapatkan urutan pengurutan yang tepat.
Matriks dasar
Jika Anda hanya ingin tabel 0
sebuah 1
dimana x = y
, ini bisa lebih murah:
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 membangun yang Anda berikan di komentar.
Perhatikan bahwa sqlfiddle.com saat ini memiliki bug yang mematikan tampilan nilai array. Jadi saya melemparkan ke text
ada untuk mengatasinya.