PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

PostgreSQL unnest() dengan nomor elemen

Postgres 9.4 atau lebih baru

Gunakan WITH ORDINALITY untuk fungsi set-return:

Ketika sebuah fungsi di FROM klausa diakhiri dengan WITH ORDINALITY , sebuahbigint kolom ditambahkan ke output yang dimulai dari 1 dan bertambah 1 untuk setiap baris output fungsi. Ini sangat berguna dalam kasus set kembali fungsi seperti unnest() .

Dikombinasikan 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, bahkan jika ekspresi tabel di sebelah kanan tidak mengembalikan baris. Jika itu bukan masalah, Anda dapat menggunakan ini jika tidak setara, kurang bertele-tele formulir dengan CROSS JOIN LATERAL implicit implisit :

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 array aktual (arr menjadi kolom array):

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 tabel dan alias kolom. Nama default dari kolom ordinalitas yang ditambahkan adalah ordinality . Tetapi lebih baik (lebih aman, lebih bersih) untuk menambahkan alias kolom eksplisit dan kolom yang memenuhi syarat tabel.

Postgres 8.4 - 9.3

Dengan row_number() OVER (PARTITION BY id ORDER BY elem) Anda mendapatkan nomor sesuai dengan urutannya, bukan nomor urut dari posisi ordinal 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 belum pernah melihatnya gagal dalam kueri sederhana, PostgreSQL tidak menegaskan apa pun tentang urutan baris tanpa ORDER BY . Itu berhasil 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 array aktual :

SELECT id, arr[nr] AS elem, nr
FROM  (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t;

Jawaban terkait di dba.SE:

  • Bagaimana cara mempertahankan urutan asli elemen dalam larik tak bersarang?

Postgres 8.1 - 8.4

Belum ada satu pun dari fitur ini yang tersedia: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 khususnya, bahwa indeks array dapat berbeda dari posisi ordinal elemen. Pertimbangkan demo ini dengan fungsi yang diperluas :

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[])  --  short for: '[1:3]={a,b,c}'
               , (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

Bandingkan:

  • Menormalkan subskrip larik untuk larik 1 dimensi sehingga dimulai dengan 1


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara Menghitung Perbedaan Antara Dua Timestamp di PostgreSQL

  2. Mendapatkan hasil antara dua tanggal di PostgreSQL

  3. Indeks untuk menemukan elemen dalam array JSON

  4. Pilih Postgresql hingga jumlah total tertentu tercapai

  5. Mencetak ke layar dalam file .sql postgres