如何保留未嵌套数组中元素的原始顺序?

swa*_*eck 22 postgresql parse sorting array

鉴于字符串:

'我认为 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;
Run Code Online (Sandbox Code Playgroud)

这完成了我希望做的事情的基本原理,但它没有保留原始的词序。

相关问题:
PostgreSQL unnest() with element number

Erw*_*ter 27

WITH ORDINALITY 在 Postgres 9.4 或更高版本中

新功能简化了这类问题。上面的查询现在可以简单地为:

SELECT *
FROM   regexp_split_to_table('I think Postgres is nifty', ' ') WITH ORDINALITY x(word, rn);
Run Code Online (Sandbox Code Playgroud)

或者,应用于表:

SELECT *
FROM   tbl t, regexp_split_to_table(t.my_column, ' ') WITH ORDINALITY x(word, rn);
Run Code Online (Sandbox Code Playgroud)

细节:

关于隐式LATERAL连接:

Postgres 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);
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

然而,虽然这通常有效并且我从未见过它在简单查询中中断,但 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;
Run Code Online (Sandbox Code Playgroud)

对于字符串表

添加PARTITION BY idOVER条款...

演示表:

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

我用作主键ctid的临时替代品。如果您有一个(或任何唯一的列),请改用它。

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

在没有任何不同 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;
Run Code Online (Sandbox Code Playgroud)

SQL小提琴。

回答问题

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;
Run Code Online (Sandbox Code Playgroud)

  • 用`generate_subscripts(arr, 1)`代替`generate_series(1, array_upper(arr, 1))`不好吗?为了清楚起见,我更喜欢前者。 (2认同)