Instal modul tambahan tablefunc
sekali per database, yang menyediakan fungsi crosstab()
. Sejak Postgres 9.1 Anda dapat menggunakan CREATE EXTENSION
untuk itu:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Kasus uji yang ditingkatkan
CREATE TABLE tbl (
section text
, status text
, ct integer -- "count" is a reserved word in standard SQL
);
INSERT INTO tbl VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7); -- ('C', 'Active') is missing
Bentuk sederhana - tidak cocok untuk atribut yang hilang
crosstab(text)
dengan 1 parameter masukan:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
Pengembalian:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Tidak perlu casting dan mengganti nama.
- Perhatikan yang salah hasil untuk
C
:nilai7
diisi untuk kolom pertama. Terkadang, perilaku ini diinginkan, tetapi tidak untuk kasus penggunaan ini. - Bentuk sederhana juga terbatas pada tepat tiga kolom dalam kueri input yang disediakan:row_name , kategori , nilai . Tidak ada ruang untuk kolom tambahan seperti pada alternatif 2 parameter di bawah ini.
Formulir aman
crosstab(text, text)
dengan 2 parameter masukan:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- could also just be "ORDER BY 1" here
, $$VALUES ('Active'::text), ('Inactive')$$
) AS ct ("Section" text, "Active" int, "Inactive" int);
Pengembalian:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Perhatikan hasil yang benar untuk
C
. -
parameter kedua dapat berupa kueri apa pun yang mengembalikan satu baris per atribut yang cocok dengan urutan definisi kolom di bagian akhir. Seringkali Anda ingin menanyakan atribut yang berbeda dari tabel yang mendasarinya seperti ini:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
Itu ada di manual.
Karena Anda tetap harus mengeja semua kolom dalam daftar definisi kolom (kecuali untuk crosstabN()
varian), biasanya lebih efisien untuk memberikan daftar pendek dalam VALUES
ekspresi seperti yang ditunjukkan:
$$VALUES ('Active'::text), ('Inactive')$$)
Atau (tidak ada di manual):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
Saya menggunakan kutipan dolar untuk membuat kutipan lebih mudah.
-
Anda bahkan dapat menampilkan kolom dengan berbeda tipe data dengan
crosstab(text, text)
- selama representasi teks dari kolom nilai adalah input yang valid untuk jenis target. Dengan cara ini Anda mungkin memiliki atribut yang berbeda jenis dan menghasilkantext
,date
,numeric
dll untuk atribut masing-masing. Ada contoh kode di akhir babcrosstab(text, text)
dalam manual.
db<>main biola di sini
Efek dari baris masukan yang berlebihan
Baris input berlebih ditangani secara berbeda - baris duplikat untuk kombinasi ("row_name", "category") yang sama - (section, status)
dalam contoh di atas.
1-parameter form mengisi kolom nilai yang tersedia dari kiri ke kanan. Nilai berlebih dibuang.
Baris masukan sebelumnya menang.
2-parameter form menetapkan setiap nilai masukan ke kolom khusus, menimpa tugas sebelumnya.
Baris masukan selanjutnya menang.
Biasanya, Anda tidak memiliki duplikat untuk memulai. Tetapi jika Anda melakukannya, sesuaikan urutan pengurutan dengan kebutuhan Anda dengan hati-hati - dan dokumentasikan apa yang terjadi.
Atau dapatkan hasil arbitrer cepat jika Anda tidak peduli. Waspadai efeknya.
Contoh lanjutan
-
Pivot pada Beberapa Kolom menggunakan Tablefunc - juga menunjukkan "kolom tambahan" yang disebutkan
-
Alternatif dinamis untuk pivot dengan CASE dan GROUP BY
\crosstabview
di psql
Postgres 9.6 menambahkan perintah-meta ini ke terminal interaktif default psql. Anda dapat menjalankan kueri yang akan Anda gunakan sebagai crosstab()
pertama parameter dan masukkan ke \crosstabview
(segera atau di langkah berikutnya). Seperti:
db=> SELECT section, status, ct FROM tbl \crosstabview
Hasil serupa seperti di atas, tetapi merupakan fitur representasi di sisi klien khusus. Baris input diperlakukan sedikit berbeda, oleh karena itu ORDER BY
tidak diperlukan. Detail untuk \crosstabview
dalam manual. Ada lebih banyak contoh kode di bagian bawah halaman itu.
Jawaban terkait di dba.SE oleh Daniel Vérité (penulis fitur psql):
- Bagaimana cara menghasilkan CROSS JOIN berporos di mana definisi tabel yang dihasilkan tidak diketahui?