Postgres 9.4 atau lebih baru
Gunakan WITH ORDINALITY
untuk fungsi set-return:
Jika fungsi dalam FROM
klausa diakhiri dengan WITH ORDINALITY
,
bigint
kolom ditambahkan ke keluaran yang dimulai dari 1 dan bertambah 1 untuk setiap baris keluaran fungsi. Ini paling berguna dalam kasus set mengembalikan fungsi seperti unnest()
.
Dalam kombinasi dengan LATERAL
fitur di pg 9.3+ , dan menurut utas ini di pgsql-hackers , kueri di atas sekarang dapat ditulis sebagai:
SELECT t.id, a.elem, a.nr
FROM tbl AS t
LEFT JOIN LATERAL unnest(string_to_array(t.elements, ','))
WITH ORDINALITY AS a(elem, nr) ON TRUE;
LEFT JOIN ... ON TRUE
mempertahankan semua baris di tabel kiri, meskipun ekspresi tabel di kanan tidak menghasilkan baris. Jika itu bukan urusan Anda, Anda dapat menggunakan bentuk yang setara ini, lebih sedikit verbose dengan implisit CROSS JOIN LATERAL
:
SELECT t.id, a.elem, a.nr
FROM tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr);
Atau lebih sederhana jika didasarkan pada larik sebenarnya ( arr
berupa kolom larik):
SELECT t.id, a.elem, a.nr
FROM tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr);
Atau bahkan, dengan sintaks minimal:
SELECT id, a, ordinality
FROM tbl, unnest(arr) WITH ORDINALITY a;
a
secara otomatis menjadi alias tabel dan kolom. Nama default dari kolom ordinalitas yang ditambahkan adalah ordinality
. Tapi lebih baik (lebih aman, lebih bersih) menambahkan alias kolom eksplisit dan kolom kualifikasi tabel.
Postgres 8.4 - 9.3
Dengan row_number() OVER (PARTITION BY id ORDER BY elem)
Anda mendapatkan nomor sesuai dengan urutan urutan, bukan nomor urut dari posisi urutan asli dalam string.
Anda cukup menghilangkan ORDER BY
:
SELECT *, row_number() OVER (PARTITION by id) AS nr
FROM (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t;
Meskipun ini biasanya berfungsi dan saya tidak pernah melihatnya gagal dalam kueri sederhana, PostgreSQL tidak menegaskan apa pun tentang urutan baris tanpa ORDER BY
. Itu terjadi untuk bekerja karena detail implementasi.
Untuk menjamin nomor urut elemen dalam string yang dipisahkan kosong :
SELECT id, arr[nr] AS elem, nr
FROM (
SELECT *, generate_subscripts(arr, 1) AS nr
FROM (SELECT id, string_to_array(elements, ' ') AS arr FROM tbl) t
) sub;
Atau lebih sederhana jika didasarkan pada larik sebenarnya :
SELECT id, arr[nr] AS elem, nr
FROM (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t;
Jawaban terkait di dba.SE:
Postgres 8.1 - 8.4
Tak satu pun dari fitur ini tersedia, namun: RETURNS TABLE
, generate_subscripts()
, unnest()
, array_length()
. Tapi ini berhasil:
CREATE FUNCTION f_unnest_ord(anyarray, OUT val anyelement, OUT ordinality integer)
RETURNS SETOF record
LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1
FROM generate_series(array_lower($1,1), array_upper($1,1)) i';
Perhatikan secara khusus, bahwa indeks larik dapat berbeda dari posisi ordinal elemen. Pertimbangkan demo ini dengan fungsi tambahan :
CREATE FUNCTION f_unnest_ord_idx(anyarray, OUT val anyelement, OUT ordinality int, OUT idx int)
RETURNS SETOF record
LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1, i
FROM generate_series(array_lower($1,1), array_upper($1,1)) i';
SELECT id, arr, (rec).*
FROM (
SELECT *, f_unnest_ord_idx(arr) AS rec
FROM (VALUES (1, '{a,b,c}'::text[])
, (2, '[5:7]={a,b,c}')
, (3, '[-9:-7]={a,b,c}')
) t(id, arr)
) sub;
id | arr | val | ordinality | idx
1 | {a,b,c} | a | 1 | 1
1 | {a,b,c} | b | 2 | 2
1 | {a,b,c} | c | 3 | 3
2 | [5:7]={a,b,c} | a | 1 | 5
2 | [5:7]={a,b,c} | b | 2 | 6
2 | [5:7]={a,b,c} | c | 3 | 7
3 | [-9:-7]={a,b,c} | a | 1 | -9
3 | [-9:-7]={a,b,c} | b | 2 | -8
3 | [-9:-7]={a,b,c} | c | 3 | -7
Membandingkan:
WITH ORDINALITY
lebih disukaigenerate_subscripts()
? Sepertinya sayagenerate_subscripts()
lebih baik karena ini menunjukkan lokasi elemen sebenarnya dalam array. Ini berguna, misalnya, saat memperbarui larik ... haruskah saya menggunakanWITH ORDINALITY
?WITH ORDINALITY
adalah solusi umum untuk mendapatkan nomor baris untuk setiap fungsi yang mengembalikan set dalam kueri SQL. Ini adalah cara tercepat, andal, dan juga bekerja dengan sempurna untuk array 1-dimensi, berbasis 1 (default untuk array Postgres, pertimbangkan ini ). Jika Anda bekerja dengan jenis array lain (kebanyakan orang tidak), dan Anda benar-benar perlu mempertahankan / bekerja dengan subskrip asli, makagenerate_subscripts()
itulah cara yang harus dilakukan. Tapiunnest()
meratakan segalanya untuk memulai dengan ...Table functions appearing in FROM can also be preceded by the key word LATERAL, but for functions the key word is optional; the function's arguments can contain references to columns provided by preceding FROM items in any case.
Mencoba:
select v.*, row_number() over (partition by id order by elem) rn from (select id, unnest(string_to_array(elements, ',')) AS elem from myTable) v
sumber
Gunakan Fungsi Pembuatan Subskrip .
http://www.postgresql.org/docs/current/static/functions-srf.html#FUNCTIONS-SRF-SUBSCRIPTS
Sebagai contoh:
SELECT id , elements[i] AS elem , i AS nr FROM ( SELECT id , elements , generate_subscripts(elements, 1) AS i FROM ( SELECT id , string_to_array(elements, ',') AS elements FROM myTable ) AS foo ) bar ;
Lebih sederhananya:
SELECT id , unnest(elements) AS elem , generate_subscripts(elements, 1) AS nr FROM ( SELECT id , string_to_array(elements, ',') AS elements FROM myTable ) AS foo ;
sumber
Jika urutan elemen tidak penting, Anda bisa
select id, elem, row_number() over (partition by id) as nr from ( select id, unnest(string_to_array(elements, ',')) AS elem from myTable ) a
sumber
unnest2()
sebagai latihanVersi lama sebelum pg v8.4 membutuhkan definisi pengguna
unnest()
. Kita dapat mengadaptasi fungsi lama ini untuk mengembalikan elemen dengan indeks:CREATE FUNCTION unnest2(anyarray) RETURNS setof record AS $BODY$ SELECT $1[i], i FROM generate_series(array_lower($1,1), array_upper($1,1)) i; $BODY$ LANGUAGE sql IMMUTABLE;
sumber
RETURNS TABLE
belum ada. Saya menambahkan satu bab ke jawaban saya yang membahas solusi.setof record
.