Mendasarkan jawaban saya pada tabel berbentuk:
CREATE TABLE tbl (
sl_no int
, username text
, designation text
, salary int
);
Setiap baris menghasilkan kolom baru untuk dikembalikan. Dengan tipe pengembalian dinamis seperti ini, hampir tidak mungkin untuk membuat ini sepenuhnya dinamis dengan satu panggilan ke database. Mendemonstrasikan solusi dengan dua langkah :
- Buat kueri
- Jalankan kueri yang dibuat
Umumnya, ini dibatasi oleh jumlah kolom maksimum yang dapat ditampung oleh sebuah tabel. Jadi bukan pilihan untuk tabel dengan lebih dari 1600 baris (atau kurang). Detail:
- Berapa jumlah maksimum kolom dalam kueri pemilihan PostgreSQL
Postgres 9.3 atau lebih lama
Solusi dinamis dengan crosstab()
- Sepenuhnya dinamis, berfungsi untuk tabel apa pun. Berikan nama tabel dalam dua tempat:
SELECT 'SELECT *
FROM crosstab(
''SELECT unnest(''' || quote_literal(array_agg(attname))
|| '''::text[]) AS col
, row_number() OVER ()
, unnest(ARRAY[' || string_agg(quote_ident(attname)
|| '::text', ',') || ']) AS val
FROM ' || attrelid::regclass || '
ORDER BY generate_series(1,' || count(*) || '), 2''
) t (col text, '
|| (SELECT string_agg('r'|| rn ||' text', ',')
FROM (SELECT row_number() OVER () AS rn FROM tbl) t)
|| ')' AS sql
FROM pg_attribute
WHERE attrelid = 'tbl'::regclass
AND attnum > 0
AND NOT attisdropped
GROUP BY attrelid;
Dapat dibungkus menjadi fungsi dengan satu parameter ...
Menghasilkan kueri dalam bentuk:
SELECT *
FROM crosstab(
'SELECT unnest(''{sl_no,username,designation,salary}''::text[]) AS col
, row_number() OVER ()
, unnest(ARRAY[sl_no::text,username::text,designation::text,salary::text]) AS val
FROM tbl
ORDER BY generate_series(1,4), 2'
) t (col text, r1 text,r2 text,r3 text,r4 text)
Menghasilkan hasil yang diinginkan:
col r1 r2 r3 r4
-----------------------------------
sl_no 1 2 3 4
username A B C D
designation XYZ RTS QWE HGD
salary 10000 50000 20000 34343
Solusi sederhana dengan unnest()
SELECT 'SELECT unnest(''{sl_no, username, designation, salary}''::text[] AS col)
, ' || string_agg('unnest('
|| quote_literal(ARRAY[sl_no::text, username::text, designation::text, salary::text])
|| '::text[]) AS row' || sl_no, E'\n , ') AS sql
FROM tbl;
- Lambat untuk tabel dengan lebih dari beberapa kolom.
Menghasilkan kueri dalam bentuk:
SELECT unnest('{sl_no, username, designation, salary}'::text[]) AS col
, unnest('{10,Joe,Music,1234}'::text[]) AS row1
, unnest('{11,Bob,Movie,2345}'::text[]) AS row2
, unnest('{12,Dave,Theatre,2356}'::text[]) AS row3
, unnest('{4,D,HGD,34343}'::text[]) AS row4
Hasil yang sama.
Postgres 9.4+
Solusi dinamis dengan crosstab()
Gunakan ini jika Anda bisa. Mengalahkan sisanya.
SELECT 'SELECT *
FROM crosstab(
$ct$SELECT u.attnum, t.rn, u.val
FROM (SELECT row_number() OVER () AS rn, * FROM '
|| attrelid::regclass || ') t
, unnest(ARRAY[' || string_agg(quote_ident(attname)
|| '::text', ',') || '])
WITH ORDINALITY u(val, attnum)
ORDER BY 1, 2$ct$
) t (attnum bigint, '
|| (SELECT string_agg('r'|| rn ||' text', ', ')
FROM (SELECT row_number() OVER () AS rn FROM tbl) t)
|| ')' AS sql
FROM pg_attribute
WHERE attrelid = 'tbl'::regclass
AND attnum > 0
AND NOT attisdropped
GROUP BY attrelid;
Beroperasi dengan attnum
alih-alih nama kolom yang sebenarnya. Lebih sederhana dan lebih cepat. Gabungkan hasilnya ke pg_attribute
sekali lagi atau integrasikan nama kolom seperti pada contoh pg 9.3.
Menghasilkan kueri dalam bentuk:
SELECT *
FROM crosstab(
$ct$SELECT u.attnum, t.rn, u.val
FROM (SELECT row_number() OVER () AS rn, * FROM tbl) t
, unnest(ARRAY[sl_no::text,username::text,designation::text,salary::text])
WITH ORDINALITY u(val, attnum)
ORDER BY 1, 2$ct$
) t (attnum bigint, r1 text, r2 text, r3 text, r4 text);
Ini menggunakan berbagai macam fitur canggih. Terlalu banyak untuk dijelaskan.
Solusi sederhana dengan unnest()
Satu unnest()
sekarang dapat mengambil beberapa larik untuk dihapus secara paralel.
SELECT 'SELECT * FROM unnest(
''{sl_no, username, designation, salary}''::text[]
, ' || string_agg(quote_literal(ARRAY[sl_no::text, username::text, designation::text, salary::text])
|| '::text[]', E'\n, ')
|| E') \n AS t(col,' || string_agg('row' || sl_no, ',') || ')' AS sql
FROM tbl;
Hasil:
SELECT * FROM unnest(
'{sl_no, username, designation, salary}'::text[]
,'{10,Joe,Music,1234}'::text[]
,'{11,Bob,Movie,2345}'::text[]
,'{12,Dave,Theatre,2356}'::text[])
AS t(col,row1,row2,row3,row4)
SQL Fiddle berjalan pada hal 9.3.