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


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()


您要处理一个字符串还是整个字符串表?如果是这样,该表是否具有主键?
Erwin Brandstetter,2012年

@ErwinBrandstetter表中的一个字符串(确实有一个主键)
swasheck 2012年

Answers:


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联接:

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);

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 idOVER条款...

演示表:

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;

此方法无需任何独特的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提琴。

回答问题

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-in-SELECT-list行为: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 2012年

1
@Erwin您是否看到过Depesz的WITH ORDINALITY帖子
杰克·道格拉斯

1
@JackDouglas:碰巧的是,星期五我们讨论了一个相关主题,这使我也有类似的发现。我在答案中加了一点。
Erwin Brandstetter

1
“详细信息”的链接仅链接到该页面。令人困惑。
通配符
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.