Bagaimana cara mempertahankan urutan elemen asli dalam array yang tidak diuji?

19

Diberikan string:

'Saya pikir PostgreSQL bagus'

Saya ingin beroperasi pada kata-kata individual yang ditemukan dalam string itu. Pada dasarnya, saya memiliki yang terpisah dari mana saya bisa mendapatkan rincian kata dan ingin bergabung dengan array string yang tidak diuji pada kamus ini.

Sejauh ini saya punya:

select word, meaning, partofspeech
from unnest(string_to_array('I think that PostgreSQL is nifty',' ')) as word
from table t
join dictionary d
on t.word = d.wordname;

Ini mencapai dasar-dasar dari apa yang saya harapkan untuk dilakukan, tetapi itu tidak mempertahankan urutan kata aslinya.

Pertanyaan terkait:
PostgreSQL undest () dengan nomor elemen

swasheck
sumber
Apakah Anda ingin memproses satu string atau seluruh tabel string ? Jika demikian, apakah tabel memiliki kunci utama?
Erwin Brandstetter
@ErwinBrandstetter satu string dalam sebuah tabel (yang memang memiliki kunci utama)
swasheck

Jawaban:

24

WITH ORDINALITY dalam Postgres 9.4 atau lebih baru

Fitur baru menyederhanakan kelas masalah ini. Kueri di atas sekarang dapat berupa:

SELECT *
FROM   regexp_split_to_table('I think Postgres is nifty', ' ') WITH ORDINALITY x(word, rn);

Atau, diterapkan pada tabel:

SELECT *
FROM   tbl t, regexp_split_to_table(t.my_column, ' ') WITH ORDINALITY x(word, rn);

Detail:

Tentang LATERALgabung implisit :

Postgres 9.3 atau lebih tinggi - dan penjelasan yang lebih umum

Untuk satu string

Anda dapat menerapkan fungsi jendela row_number()untuk mengingat urutan elemen. Namun, dengan biasa row_number() OVER (ORDER BY col)Anda mendapatkan angka sesuai urutan , bukan posisi awal dalam string.

Anda bisa dengan mudah menghilangkan ORDER BYuntuk mendapatkan posisi "apa adanya":

SELECT *, row_number() OVER () AS rn
FROM   regexp_split_to_table('I think Postgres is nifty', ' ') AS x(word);

Performa regexp_split_to_table()menurunkan dengan string panjang. unnest(string_to_array(...))skala lebih baik:

SELECT *, row_number() OVER () AS rn
FROM   unnest(string_to_array('I think Postgres is nifty', ' ')) AS x(word);

Namun, sementara ini biasanya bekerja dan saya belum pernah melihatnya memecah dalam pertanyaan sederhana, Postgres tidak menegaskan apa pun tentang urutan baris tanpa eksplisit ORDER BY.

Untuk menjamin jumlah elemen dalam string asli, gunakan generate_subscript()(ditingkatkan dengan komentar oleh @deszo):

SELECT arr[rn] AS word, rn
FROM   (
   SELECT *, generate_subscripts(arr, 1) AS rn
   FROM   string_to_array('I think Postgres is nifty', ' ') AS x(arr)
   ) y;

Untuk daftar string

Tambahkan PARTITION BY idke OVERklausa ...

Tabel demo:

CREATE TEMP TABLE strings(string text);
INSERT INTO strings VALUES
  ('I think Postgres is nifty')
 ,('And it keeps getting better');

Saya menggunakan ctidsebagai pengganti ad-hoc untuk kunci utama . Jika Anda memiliki satu (atau kolom unik ) gunakan saja.

SELECT *, row_number() OVER (PARTITION BY ctid) AS rn
FROM  (
   SELECT ctid, unnest(string_to_array(string, ' ')) AS word
   FROM   strings
   ) x;

Ini berfungsi tanpa ID berbeda:

SELECT arr[rn] AS word, rn
FROM  (
   SELECT *, generate_subscripts(arr, 1) AS rn
   FROM  (
      SELECT string_to_array(string, ' ') AS arr
      FROM   strings
      ) x
   ) y;

SQL Fiddle.

Jawab pertanyaan

SELECT z.arr, z.rn, z.word, d.meaning   -- , partofspeech -- ?
FROM  (
   SELECT *, arr[rn] AS word
   FROM  (
      SELECT *, generate_subscripts(arr, 1) AS rn
      FROM  (
         SELECT string_to_array(string, ' ') AS arr
         FROM   strings
         ) x
      ) y
   ) z
JOIN   dictionary d ON d.wordname = z.word
ORDER  BY z.arr, z.rn;
Erwin Brandstetter
sumber
1
Anda juga dapat memanfaatkan Pg ini unik perilaku SRF-in-SELECT-list: SELECT generate_series(1,array_length(word_array,1)), unnest(word_array) FROM ..... 9.3 LATERALdapat memberikan solusi yang lebih baik untuk masalah ini.
Craig Ringer
2
Tidak akan generate_subscripts(arr, 1)berhasilgenerate_series(1, array_upper(arr, 1)) ? Saya lebih suka yang pertama untuk kejelasan.
dezso
1
@Erwin, Anda sudah melihat ini DENGAN postingan ORDINALITY dari depesz?
Jack Douglas
1
@JackDouglas: Ketika itu terjadi, kami berdiskusi tentang topik terkait pada hari Jumat , yang membawa saya pada penemuan serupa. Saya menambahkan sedikit ke jawabannya.
Erwin Brandstetter
1
Tautan untuk "detail" hanya tautan ke halaman yang sama ini. Itu membingungkan.
Wildcard