Як зберегти початковий порядок елементів у нестримованому масиві?


19

Враховуючи рядок:

"Я думаю, що PostgreSQL чудовий"

Я хотів би оперувати окремими словами, знайденими в цьому рядку. По суті, у мене є окремий розділ, з якого я можу отримати детальну інформацію про слово, і я хотів би приєднати до цього словника нестримований масив цього рядка.

Поки що я маю:

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;

Це виконує основи того, що я сподівався зробити, але це не зберігає початковий порядок слів.

Пов'язане питання:
PostgreSQL unnest () з номером елемента


Ви хочете обробити один рядок або цілу таблицю рядків ? Якщо так, чи має таблиця первинний ключ?
Ервін Брандстеттер

@ErwinBrandstetter одна рядок у таблиці (у якої є первинний ключ)
swasheck

Відповіді:


24

WITH ORDINALITY у Postgres 9.4 або пізнішої версії

Нова функція спрощує цей клас проблем. Наведений вище запит тепер може бути просто:

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

Або застосовано до таблиці:

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

Деталі:

Про неявне LATERALприєднання:

Постгреси 9.3 або старші - і більш загальне пояснення

Для однієї струни

Ви можете застосувати функцію вікна, row_number()щоб запам'ятати порядок елементів. Однак зі звичайними row_number() OVER (ORDER BY col)ви отримуєте числа відповідно до порядку сортування , а не вихідного положення в рядку.

Ви можете просто пропустити ORDER BYпозицію "як є":

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

Виконання regexp_split_to_table()деградів з довгими струнами. unnest(string_to_array(...))ваги краще:

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

Однак, хоча це нормально працює, і я ніколи не бачив, щоб він порушувався у простих запитах, Postgres не стверджує нічого про порядок рядків без явного ORDER BY.

Щоб гарантувати порядкові номери елементів у вихідному рядку, використовуйте generate_subscript()(покращене коментарем @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;

Для таблиці рядків

Додати PARTITION BY idдо OVERпункту ...

Демонстраційна таблиця:

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

Я використовую ctidяк спеціальний замінник первинного ключа . Якщо у вас є один (або будь-який унікальний стовпець ), використовуйте це замість цього.

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

Це працює без чіткого ідентифікатора:

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.

Відповідь на запитання

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
Ви можете також використовувати виверткий поведінку Pg в SRF-в-список вибору: SELECT generate_series(1,array_length(word_array,1)), unnest(word_array) FROM ..... 9.3 LATERALможе запропонувати кращі рішення цієї проблеми.
Крейг Рінгер

2
Не generate_subscripts(arr, 1)працювали б замість цього generate_series(1, array_upper(arr, 1))? Я б віддав перевагу першому для наочності.
dezso

1
@Erwin Ви бачили це з публікацією про ORDINALITY від depesz?
Джек Дуглас

1
@JackDouglas: Як це трапляється, у нас у п’ятницю було обговорено пов’язану тему , яка привела мене до подібного відкриття. Я трохи додав у відповідь.
Ервін Брандштеттер

1
Посилання на "подробиці" просто посилається на цю ж сторінку. Це заплутано.
Wildcard
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.