Sınırsız bir dizideki öğelerin orijinal sırasını nasıl koruyabilirim?


19

Dize verildiğinde:

'PostgreSQL'in şık olduğunu düşünüyorum'

Bu dize içinde bulunan tek tek kelimeler üzerinde çalışmak istiyorum. Aslında, ben kelime ayrıntılarını alabilirsiniz ve bu sözlükte bu dizenin unnested bir dizi katılmak istiyorum ayrı bir var.

Şimdiye kadar var:

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;

Bu, yapmayı umduğum şeyin temellerini gerçekleştirir, ancak orijinal kelime sırasını korumaz.

İlgili soru:
Öğe numarası ile PostgreSQL unnest ()


Birini işlemek ister misin dizeyi veya dizelerin tamamını içeren bir tabloyu ? Öyleyse, tablonun birincil anahtarı var mı?
Erwin Brandstetter

Bir tabloda bir dize @ErwinBrandstetter (yani birincil anahtara sahip etmez)
swasheck

Yanıtlar:


24

WITH ORDINALITY Postgres 9.4 veya sonrasında

Yeni özellik, bu sınıftaki sorunları basitleştirir. Yukarıdaki sorgu şimdi olabilir:

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

Veya bir tabloya uygulanır:

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

Detaylar:

Örtülü LATERALbirleştirme hakkında:

Postgres 9.3 veya daha eski - ve daha genel açıklama

Tek bir dize için

row_number()Öğelerin sırasını hatırlamak için pencere işlevini uygulayabilirsiniz . Ancak, her zamanki ile row_number() OVER (ORDER BY col)size göre rakamları elde orijinal konuma değil, sıralama düzenine .

Sadece atlayabilirsiniz ORDER BY gibi" konumunu almayı :

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

Performansı regexp_split_to_table()Uzun telli bozunmaların . unnest(string_to_array(...))daha iyi ölçeklendirir:

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

Ancak, bu süre normal olarak çalışır ve ben basit sorgularda kırılmış görmedim, Postgres açık bir satır olmadan sıra olarak hiçbir şey ileri sürüyor ORDER BY.

Orijinal dizedeki sıralı öğe sayısını garanti etmek için şunu kullanın:generate_subscript() (@deszo'nun yorumuyla geliştirildi):

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;

Bir dizgi tablosu için

Ekle PARTITION BY id için OVERfıkra ...

Demo tablosu:

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

Birincil anahtarctid için geçici yedek olarak kullanıyorum . Bir tane (veya benzersiz bir sütun ) varsa bunu kullanın.

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

Bu, farklı bir kimlik olmadan çalışır:

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.

Sorunun cevabı

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;

1
Ayrıca Pg en ilginç SRF-in-SEÇ-listesinin davranışını istismar edebilirsiniz: SELECT generate_series(1,array_length(word_array,1)), unnest(word_array) FROM ..... 9.3'ler LATERALbu soruna daha iyi çözümler sağlayabilir.
Craig Ringer

2
generate_subscripts(arr, 1)Bunun yerine çalışmaz mıydı generate_series(1, array_upper(arr, 1))? Birincisini netlik için tercih ederim.
dezso

1
Bunu bir @Erwin İLE ordinal yazı depesz gelen?
Jack Douglas

1
@JackDouglas: Olduğu gibi , Cuma günü ilgili bir konu hakkında bir tartışma yaptık , bu da beni benzer bir keşfe götürdü . Cevaba biraz ekledim.
Erwin Brandstetter

1
"Ayrıntılar" bağlantısı aynı sayfaya bağlanır. Bu kafa karıştırıcı.
Wildcard
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.