it-swarm-eu.dev

Jak zachovat původní pořadí prvků v netestovaném poli?

Vzhledem k řetězci:

"Myslím, že PostgreSQL je šikovný"

Rád bych pracoval na jednotlivých slovech nalezených v tomto řetězci. V zásadě mám samostatnou část, od které mohu získat podrobnosti o aplikaci Word, a rád bych se připojil k netestovanému souboru tohoto řetězce v tomto slovníku.

Zatím mám:

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;

Tím se dosáhne základů toho, co jsem doufal, ale nezachovává se původní pořadí slov.

Související otázka:
PostgreSQL unnest () s číslem prvk

19
swasheck

WITH ORDINALITY V Postgresu 9.4 nebo novější

Nová funkce zjednodušuje tuto třídu problémů. Výše uvedený dotaz může nyní být jednoduše:

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

Nebo aplikováno na tabulku:

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

Podrobnosti:

O implicitním LATERAL join:

Postgres 9,3 nebo starší - a obecnější vysvětlení

Pro jeden řetězec

Funkci okna row_number() můžete použít k zapamatování pořadí prvků. S obvyklým row_number() OVER (ORDER BY col) však získáváte čísla podle pořadí řazení , nikoli podle původní pozice v řetězci.

Dalo by se jednoduše vynechat ORDER BY A získat tak pozici „tak, jak je“:

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

Výkon regexp_split_to_table() klesá s dlouhými řetězci. unnest(string_to_array(...)) měřítka lépe:

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

Přestože to normálně funguje a nikdy jsem ho neviděl v jednoduchých dotazech prosazovat, Postgres netvrdí nic o pořadí řádků bez explicitního ORDER BY.

Chcete-li zaručit pořadová čísla prvků v původním řetězci, použijte generate_subscript() (vylepšeno s komentářem od @ 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;

Pro tabulku řetězců

Přidejte PARTITION BY id Do klauzule OVER ...

Ukázková tabulka:

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

Jako náhradu ad-hoc za primární klíč používám ctid. Pokud máte jeden (nebo jakýkoli jedinečný sloupec ), použijte jej.

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

Toto funguje bez jakéhokoli odlišného ID:

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.

Odpověď na otázku

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;
24
Erwin Brandstetter